diff --git a/ChangeLog b/ChangeLog index 824737c04..d368af1f8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +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 diff --git a/doc/dev.html b/doc/dev.html index 48a96e7a7..22ee142bb 100644 --- a/doc/dev.html +++ b/doc/dev.html @@ -4,7 +4,7 @@ Ejabberd Developers Guide - + @@ -21,7 +21,7 @@ mailto:alexey@sevcom.net
xmpp:aleksey@jabber.ru -

September 10, 2003

+

August 21, 2005

@@ -47,11 +47,12 @@
  • 2  XML representation
  • 3  Module xml -
  • 4  ejabberd modules +
  • 4  Module xml_stream +
  • 5  ejabberd modules @@ -90,9 +91,6 @@ Works on most of popular platforms: *nix (tested on Linux, FreeBSD and
  • Support for Statistics Gathering.
  • Support for xml:lang -ejabberd is a Free and Open Source fault-tolerant distributed Jabber -server. It is written mostly in Erlang.
    -

    1.1  How it works

    @@ -158,7 +156,7 @@ does not exist, then it is opened and registered.

    2  XML representation

    -Each XML stanza represented as following tuple: +Each XML stanza is represented as the following tuple:
     XMLElement = {xmlelement, Name, Attrs, [ElementOrCDATA]}
             Name = string()
    @@ -173,7 +171,7 @@ XMLElement = {xmlelement, Name, Attrs, [ElementOrCDATA]}
     <message to='test@conference.example.org' type='groupchat'>
       <body>test</body>
     </message>
    -
    represented as following structure: +is represented as the following structure:
     {xmlelement, "message",
         [{"to", "test@conference.example.org"},
    @@ -233,21 +231,34 @@ Res = string() | XMLElement
              get_tag_attr/2, get_tag_attr_s/2
              get_subtag/2
     
    + + +

    4  Module xml_stream

    + + +
    +parse_element(Str) -> XMLElement | {error, Err}
    +
    +Str = string()
    +Err = term()
    +
    Parses Str using XML parser, returns either parsed element or error + tuple. +
    -

    4  ejabberd modules

    +

    5  ejabberd modules

    -

    4.1  gen_mod behaviour

    +

    5.1  gen_mod behaviour

    TBD

    -

    4.2  Module gen_iq_handler

    +

    5.2  Module gen_iq_handler

    The module gen_iq_handler allows to easily write handlers for IQ packets @@ -255,23 +266,25 @@ of particular XML namespaces that addressed to server or to users bare JIDs.

    In this module the following functions are defined:
    -add_iq_handler(Component, NS, Module, Function, Type)
    +add_iq_handler(Component, Host, NS, Module, Function, Type)
     Component = Module = Function = atom()
    -NS = string()
    +Host = NS = string()
     Type = no_queue | one_queue | parallel
    -
    Registers function Module:Function as handler for IQ packets that - contain child of namespace NS in Component. Queueing - discipline is Type. There are at least two components defined: +Registers function Module:Function as handler for IQ packets on + virtual host Host that contain child of namespace NS in + Component. Queueing discipline is Type. There are at least + two components defined:
    ejabberd_local
    Handles packets that addressed to server JID;
    ejabberd_sm
    Handles packets that addressed to users bare JIDs.
    -
    remove_iq_handler(Component, NS)
    +
    remove_iq_handler(Component, Host, NS)
     Component = atom()
    -NS = string()
    -
    Removes IQ handler for namespace NS from Component. +Host = NS = string() +Removes IQ handler on virtual host Host for namespace NS from + Component.
    Handler function must have the following type:
    @@ -284,8 +297,8 @@ From = To = jid() -behaviour(gen_mod). --export([start/1, - stop/0, +-export([start/2, + stop/1, process_local_iq/3]). -include("ejabberd.hrl"). @@ -293,13 +306,13 @@ From = To = jid() -define(NS_CPUTIME, "ejabberd:cputime"). -start(Opts) -> +start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_CPUTIME, + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_CPUTIME, ?MODULE, process_local_iq, IQDisc). -stop() -> - gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_CPUTIME). +stop(Host) -> + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_CPUTIME). process_local_iq(From, To, {iq, ID, Type, XMLNS, SubEl}) -> case Type of @@ -317,7 +330,7 @@ process_local_iq(From, To, {iq, ID, Type, XMLNS, SubEl}) -> -

    4.3  Services

    +

    5.3  Services

    TBD
    @@ -328,14 +341,15 @@ TODO: use proc_lib -behaviour(gen_mod). --export([start/1, init/1, stop/0]). +-export([start/2, init/1, stop/1]). -include("ejabberd.hrl"). -include("jlib.hrl"). -start(Opts) -> - Host = gen_mod:get_opt(host, Opts, "echo." ++ ?MYNAME), - register(ejabberd_mod_echo, spawn(?MODULE, init, [Host])). +start(Host, Opts) -> + MyHost = gen_mod:get_opt(host, Opts, "echo." ++ Host), + register(gen_mod:get_module_proc(Host, ?PROCNAME), + spawn(?MODULE, init, [MyHost])). init(Host) -> ejabberd_router:register_local_route(Host), @@ -347,15 +361,16 @@ loop(Host) -> ejabberd_router:route(To, From, Packet), loop(Host); stop -> - ejabberd_router:unregister_local_route(Host), + ejabberd_router:unregister_route(Host), ok; _ -> loop(Host) end. -stop() -> - ejabberd_mod_echo ! stop, - ok. +stop(Host) -> + Proc = gen_mod:get_module_proc(Host, ?PROCNAME), + Proc ! stop, + {wait, Proc}. diff --git a/doc/dev.tex b/doc/dev.tex index fcfc1ee73..26497a191 100644 --- a/doc/dev.tex +++ b/doc/dev.tex @@ -41,7 +41,7 @@ \author{Alexey Shchepin \\ \ahrefurl{mailto:alexey@sevcom.net} \\ \ahrefurl{xmpp:aleksey@jabber.ru}} -\date{September 10, 2003} +\date{August 21, 2005} \begin{document} \begin{titlepage} @@ -89,8 +89,6 @@ The main features of \ejabberd{} are: \item Support for \tjepref{0039}{Statistics Gathering}. \item Support for \ns{xml:lang} \end{itemize} -\ejabberd{} is a Free and Open Source fault-tolerant distributed \Jabber{} -server. It is written mostly in Erlang. @@ -158,7 +156,7 @@ does not exist, then it is opened and registered. \section{XML representation} \label{sec:xmlrepr} -Each XML stanza represented as following tuple: +Each XML stanza is represented as the following tuple: \begin{verbatim} XMLElement = {xmlelement, Name, Attrs, [ElementOrCDATA]} Name = string() @@ -175,7 +173,7 @@ E.\,g. this stanza: test \end{verbatim} -represented as following structure: +is represented as the following structure: \begin{verbatim} {xmlelement, "message", [{"to", "test@conference.example.org"}, @@ -245,6 +243,18 @@ Res = string() | XMLElement \end{description} +\section{Module \texttt{xml\_stream}} +\label{sec:xmlstreammod} + +\begin{description} +\item[\verb!parse_element(Str) -> XMLElement | {error, Err}!] +\begin{verbatim} +Str = string() +Err = term() +\end{verbatim} + Parses \texttt{Str} using XML parser, returns either parsed element or error + tuple. +\end{description} \section{\ejabberd{} modules} @@ -264,25 +274,27 @@ of particular XML namespaces that addressed to server or to users bare JIDs. In this module the following functions are defined: \begin{description} -\item[\verb|add_iq_handler(Component, NS, Module, Function, Type)|] +\item[\verb|add_iq_handler(Component, Host, NS, Module, Function, Type)|] \begin{verbatim} Component = Module = Function = atom() -NS = string() +Host = NS = string() Type = no_queue | one_queue | parallel \end{verbatim} - Registers function \verb|Module:Function| as handler for IQ packets that - contain child of namespace \verb|NS| in \verb|Component|. Queueing - discipline is \verb|Type|. There are at least two components defined: + Registers function \verb|Module:Function| as handler for IQ packets on + virtual host \verb|Host| that contain child of namespace \verb|NS| in + \verb|Component|. Queueing discipline is \verb|Type|. There are at least + two components defined: \begin{description} \item[\verb|ejabberd_local|] Handles packets that addressed to server JID; \item[\verb|ejabberd_sm|] Handles packets that addressed to users bare JIDs. \end{description} -\item[\verb|remove_iq_handler(Component, NS)|] +\item[\verb|remove_iq_handler(Component, Host, NS)|] \begin{verbatim} Component = atom() -NS = string() +Host = NS = string() \end{verbatim} - Removes IQ handler for namespace \verb|NS| from \verb|Component|. + Removes IQ handler on virtual host \verb|Host| for namespace \verb|NS| from + \verb|Component|. \end{description} Handler function must have the following type: @@ -300,8 +312,8 @@ From = To = jid() -behaviour(gen_mod). --export([start/1, - stop/0, +-export([start/2, + stop/1, process_local_iq/3]). -include("ejabberd.hrl"). @@ -309,13 +321,13 @@ From = To = jid() -define(NS_CPUTIME, "ejabberd:cputime"). -start(Opts) -> +start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_CPUTIME, + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_CPUTIME, ?MODULE, process_local_iq, IQDisc). -stop() -> - gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_CPUTIME). +stop(Host) -> + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_CPUTIME). process_local_iq(From, To, {iq, ID, Type, XMLNS, SubEl}) -> case Type of @@ -345,14 +357,15 @@ TODO: use \verb|proc_lib| -behaviour(gen_mod). --export([start/1, init/1, stop/0]). +-export([start/2, init/1, stop/1]). -include("ejabberd.hrl"). -include("jlib.hrl"). -start(Opts) -> - Host = gen_mod:get_opt(host, Opts, "echo." ++ ?MYNAME), - register(ejabberd_mod_echo, spawn(?MODULE, init, [Host])). +start(Host, Opts) -> + MyHost = gen_mod:get_opt(host, Opts, "echo." ++ Host), + register(gen_mod:get_module_proc(Host, ?PROCNAME), + spawn(?MODULE, init, [MyHost])). init(Host) -> ejabberd_router:register_local_route(Host), @@ -364,15 +377,16 @@ loop(Host) -> ejabberd_router:route(To, From, Packet), loop(Host); stop -> - ejabberd_router:unregister_local_route(Host), + ejabberd_router:unregister_route(Host), ok; _ -> loop(Host) end. -stop() -> - ejabberd_mod_echo ! stop, - ok. +stop(Host) -> + Proc = gen_mod:get_module_proc(Host, ?PROCNAME), + Proc ! stop, + {wait, Proc}. \end{verbatim} diff --git a/src/ejabberd_auth_odbc.erl b/src/ejabberd_auth_odbc.erl index a51683df8..a634691d3 100644 --- a/src/ejabberd_auth_odbc.erl +++ b/src/ejabberd_auth_odbc.erl @@ -122,11 +122,12 @@ dirty_get_registered_users() -> get_vh_registered_users(?MYNAME). get_vh_registered_users(Server) -> + LServer = jlib:nameprep(Server), case catch ejabberd_odbc:sql_query( - jlib:nameprep(Server), + LServer, "select username from users") of {selected, ["username"], Res} -> - [U || {U} <- Res]; + [{U, LServer} || {U} <- Res]; _ -> [] end. diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index ff24eb995..137ace03e 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -12,7 +12,7 @@ -behaviour(gen_mod). --export([start/2, init/2, stop/1, +-export([start/2, init/3, stop/1, process_local_iq/3, process_sm_iq/3, reindex_vcards/0, @@ -70,36 +70,36 @@ start(Host, Opts) -> gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_VCARD, ?MODULE, process_sm_iq, IQDisc), catch mod_disco:register_sm_feature(Host, ?NS_VCARD), - Hosts = gen_mod:get_hosts(Opts, "vjud."), + MyHost = gen_mod:get_opt(host, Opts, "vjud." ++ Host), Search = gen_mod:get_opt(search, Opts, true), register(gen_mod:get_module_proc(Host, ?PROCNAME), - spawn(?MODULE, init, [Hosts, Search])). + spawn(?MODULE, init, [MyHost, Host, Search])). -init(Hosts, Search) -> +init(Host, ServerHost, Search) -> case Search of false -> - loop(Hosts); + loop(Host, ServerHost); _ -> - ejabberd_router:register_routes(Hosts), - loop(Hosts) + ejabberd_router:register_route(Host), + loop(Host, ServerHost) end. -loop(Hosts) -> +loop(Host, ServerHost) -> receive {route, From, To, Packet} -> - case catch do_route(From, To, Packet) of + case catch do_route(ServerHost, From, To, Packet) of {'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]); _ -> ok end, - loop(Hosts); + loop(Host, ServerHost); stop -> - catch ejabberd_router:unregister_routes(Hosts), + ejabberd_router:unregister_route(Host), ok; _ -> - loop(Hosts) + loop(Host, ServerHost) end. stop(Host) -> @@ -272,7 +272,7 @@ set_vcard(User, LServer, VCARD) -> -do_route(From, To, Packet) -> +do_route(ServerHost, From, To, Packet) -> #jid{user = User, resource = Resource} = To, if (User /= "") or (Resource /= "") -> @@ -310,7 +310,7 @@ do_route(From, To, Packet) -> [{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "result"}], - search_result(Lang, To, XData) + search_result(Lang, To, ServerHost, XData) }]}]}, ejabberd_router:route( To, From, jlib:iq_to_xml(ResIQ)) @@ -420,7 +420,7 @@ find_xdata_el1([_ | Els]) -> {xmlelement, "field", [{"label", translate:translate(Lang, Label)}, {"var", Var}], []}). -search_result(Lang, JID, Data) -> +search_result(Lang, JID, ServerHost, Data) -> [{xmlelement, "title", [], [{xmlcdata, translate:translate(Lang, "Results of search in ") ++ jlib:jid_to_string(JID)}]}, @@ -437,7 +437,7 @@ search_result(Lang, JID, Data) -> ?LFIELD("email", "email"), ?LFIELD("Organization Name", "orgname"), ?LFIELD("Organization Unit", "orgunit") - ]}] ++ lists:map(fun record_to_item/1, search(JID#jid.lserver, Data)). + ]}] ++ lists:map(fun record_to_item/1, search(ServerHost, Data)). -define(FIELD(Var, Val), {xmlelement, "field", [{"var", Var}], diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl index 9c8149cf6..c2bbeb298 100644 --- a/src/mod_vcard_ldap.erl +++ b/src/mod_vcard_ldap.erl @@ -12,7 +12,7 @@ -behaviour(gen_mod). --export([start/2, init/2, stop/1, +-export([start/2, init/3, stop/1, process_local_iq/3, process_sm_iq/3, remove_user/1]). @@ -21,6 +21,7 @@ -include("eldap/eldap.hrl"). -include("jlib.hrl"). +-define(PROCNAME, ejabberd_mod_vcard_ldap). start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), @@ -28,45 +29,47 @@ start(Host, Opts) -> ?MODULE, process_local_iq, IQDisc), gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_VCARD, ?MODULE, process_sm_iq, IQDisc), - LDAPServers = ejabberd_config:get_local_option(ldap_servers), - RootDN = ejabberd_config:get_local_option(ldap_rootdn), - Password = ejabberd_config:get_local_option(ldap_password), + LDAPServers = ejabberd_config:get_local_option({ldap_servers, Host}), + RootDN = ejabberd_config:get_local_option({ldap_rootdn, Host}), + Password = ejabberd_config:get_local_option({ldap_password, Host}), eldap:start_link("mod_vcard_ldap", LDAPServers, 389, RootDN, Password), - Host = gen_mod:get_opt(host, Opts, "vjud." ++ ?MYNAME), + MyHost = gen_mod:get_opt(host, Opts, "vjud." ++ Host), Search = gen_mod:get_opt(search, Opts, true), - register(ejabberd_mod_vcard_ldap, spawn(?MODULE, init, [Host, Search])). + register(gen_mod:get_module_proc(Host, ?PROCNAME), + spawn(?MODULE, init, [MyHost, Host, Search])). -init(Host, Search) -> +init(Host, ServerHost, Search) -> case Search of false -> - loop(Host); + loop(Host, ServerHost); _ -> ejabberd_router:register_route(Host), - loop(Host) + loop(Host, ServerHost) end. -loop(Host) -> +loop(Host, ServerHost) -> receive {route, From, To, Packet} -> - case catch do_route(From, To, Packet) of + case catch do_route(ServerHost, From, To, Packet) of {'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]); _ -> ok end, - loop(Host); + loop(Host, ServerHost); stop -> - catch ejabberd_router:unregister_route(Host), + ejabberd_router:unregister_route(Host), ok; _ -> - loop(Host) + loop(Host, ServerHost) end. stop(Host) -> gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_VCARD), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_VCARD), - ejabberd_mod_vcard_ldap ! stop, - ok. + Proc = gen_mod:get_module_proc(Host, ?PROCNAME), + Proc ! stop, + {wait, Proc}. process_local_iq(_From, _To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> case Type of @@ -92,10 +95,10 @@ process_local_iq(_From, _To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) ]}]} end. -find_ldap_user(User) -> - Attr = ejabberd_config:get_local_option(ldap_uidattr), +find_ldap_user(Host, User) -> + Attr = ejabberd_config:get_local_option({ldap_uidattr, Host}), Filter = eldap:equalityMatch(Attr, User), - Base = ejabberd_config:get_local_option(ldap_base), + Base = ejabberd_config:get_local_option({ldap_base, Host}), case eldap:search("mod_vcard_ldap", [{base, Base}, {filter, Filter}, {attributes, []}]) of @@ -192,12 +195,13 @@ process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) -> set -> IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; get -> - #jid{luser = LUser} = To, - case find_ldap_user(LUser) of + #jid{luser = LUser, lserver = LServer} = To, + case find_ldap_user(LServer, LUser) of #eldap_entry{attributes = Attributes} -> Vcard = ldap_attributes_to_vcard(Attributes,From,To), IQ#iq{type = result, sub_el = Vcard}; - _ -> IQ#iq{type = result, sub_el = []} + _ -> + IQ#iq{type = result, sub_el = []} end end. @@ -234,7 +238,7 @@ process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) -> -do_route(From, To, Packet) -> +do_route(ServerHost, From, To, Packet) -> #jid{user = User, resource = Resource} = To, if (User /= "") or (Resource /= "") -> @@ -272,7 +276,7 @@ do_route(From, To, Packet) -> [{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "result"}], - search_result(Lang, To, XData) + search_result(Lang, To, ServerHost, XData) }]}]}, ejabberd_router:route( To, From, jlib:iq_to_xml(ResIQ)) @@ -382,7 +386,7 @@ find_xdata_el1([_ | Els]) -> {xmlelement, "field", [{"label", translate:translate(Lang, Label)}, {"var", Var}], []}). -search_result(Lang, JID, Data) -> +search_result(Lang, JID, ServerHost, Data) -> [{xmlelement, "title", [], [{xmlcdata, translate:translate(Lang, "Results of search in ") ++ jlib:jid_to_string(JID)}]}, @@ -401,7 +405,7 @@ search_result(Lang, JID, Data) -> ?LFIELD("Organization Unit", "orgunit") ]}] ++ lists:map(fun(E) -> record_to_item(E#eldap_entry.attributes) - end, search(JID#jid.lserver, Data)). + end, search(ServerHost, Data)). -define(FIELD(Var, Val), {xmlelement, "field", [{"var", Var}], @@ -491,8 +495,8 @@ record_to_item(Attributes) -> search(LServer, Data) -> Filter = make_filter(Data), - Base = ejabberd_config:get_local_option(ldap_base), - UIDAttr = ejabberd_config:get_local_option(ldap_uidattr), + Base = ejabberd_config:get_local_option({ldap_base, LServer}), + UIDAttr = ejabberd_config:get_local_option({ldap_uidattr, LServer}), case eldap:search("mod_vcard_ldap",[{base, Base}, {filter, Filter}, {attributes, []}]) of @@ -500,15 +504,17 @@ search(LServer, Data) -> [X || X <- E, ejabberd_auth:is_user_exists( ldap_get_value(X, UIDAttr), LServer)]; - _ -> - ?ERROR_MSG("~p", ["Bad search"]) + Err -> + ?ERROR_MSG("Bad search: ~p", [[LServer, {base, Base}, + {filter, Filter}, + {attributes, []}]]) end. make_filter(Data) -> Filter = [X || X <- lists:map(fun(R) -> make_assertion(R) - end,Data), + end, Data), X /= none ], case Filter of [F] ->