]> granicus.if.org Git - ejabberd/commitdiff
Support XEP-0157: Contact Addresses for XMPP Services (EJAB-235)
authorBadlop <badlop@process-one.net>
Fri, 17 Jul 2009 20:45:44 +0000 (20:45 +0000)
committerBadlop <badlop@process-one.net>
Fri, 17 Jul 2009 20:45:44 +0000 (20:45 +0000)
SVN Revision: 2368

doc/guide.html
doc/guide.tex
src/jlib.hrl
src/mod_disco.erl
src/mod_irc/mod_irc.erl
src/mod_muc/mod_muc.erl
src/mod_proxy65/mod_proxy65_service.erl
src/mod_pubsub/mod_pubsub.erl
src/mod_vcard.erl
src/mod_vcard_ldap.erl
src/mod_vcard_odbc.erl

index 50daeb690b683cfa806ecf90b12f71851cfb4e70..2d1fb8eaa5822aaf2a08e9518a51d4d3d3f920dd 100644 (file)
@@ -1958,6 +1958,7 @@ disabled for instances of <TT>ejabberd</TT> with hundreds of thousands users.</P
 
 
 
+
 </P><P>This module adds support for Service Discovery (<A HREF="http://www.xmpp.org/extensions/xep-0030.html">XEP-0030</A>). With
 this module enabled, services on your server can be discovered by
 Jabber clients. Note that <TT>ejabberd</TT> has no modules with support
@@ -1969,8 +1970,16 @@ the services you offer.</P><P>Options:
 <B><TT>iqdisc</TT></B></DT><DD CLASS="dd-description"> This specifies
 the processing discipline for Service Discovery (<TT>http://jabber.org/protocol/disco#items</TT> and
 <TT>http://jabber.org/protocol/disco#info</TT>) IQ queries (see section&#XA0;<A HREF="#modiqdiscoption">3.3.2</A>).
-</DD><DT CLASS="dt-description"><B><TT>extra_domains</TT></B></DT><DD CLASS="dd-description"> With this option,
-extra domains can be added to the Service Discovery item list.
+</DD><DT CLASS="dt-description"><B><TT>{extra_domains, [ Domain ]}</TT></B></DT><DD CLASS="dd-description"> With this option,
+you can specify a list of extra domains that are added to the Service Discovery item list.
+</DD><DT CLASS="dt-description"><B><TT>{server_info, [ {Modules, Field, [Value]} ]}</TT></B></DT><DD CLASS="dd-description"> 
+Specify additional information about the server,
+as described in Contact Addresses for XMPP Services (<A HREF="http://www.xmpp.org/extensions/xep-0157.html">XEP-0157</A>).
+<TT>Modules</TT> can be the keyword &#X2018;all&#X2019;, 
+in which case the information is reported in all the services;
+or a list of <TT>ejabberd</TT> modules, 
+in which case the information is only specified for the services provided by those modules.
+Any arbitrary <TT>Field</TT> and <TT>Value</TT> can be specified, not only contact addresses.
 </DD></DL><P>Examples:
 </P><UL CLASS="itemize"><LI CLASS="li-itemize">
 To serve a link to the Jabber User Directory on <TT>jabber.org</TT>:
@@ -1996,6 +2005,28 @@ To serve a link to the Jabber User Directory on <TT>jabber.org</TT>:
                                 "example.com"]}]},
   ...
  ]}.
+</PRE></LI><LI CLASS="li-itemize">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:
+<PRE CLASS="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"]}
+  ]}]},
+  ...
+ ]}.
 </PRE></LI></UL><P> <A NAME="modecho"></A> </P><!--TOC subsection <TT>mod_echo</TT>-->
 <H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc42">3.3.5</A>&#XA0;&#XA0;<A HREF="#modecho"><TT>mod_echo</TT></A></H3><!--SEC END --><P> <A NAME="modecho"></A> 
 </P><P>This module simply echoes any Jabber
@@ -3275,6 +3306,10 @@ Starts the Erlang system detached from the system console.
        Maximum number of Erlang processes.
 </DD><DT CLASS="dt-description"><B><TT>-remsh ejabberd@localhost</TT></B></DT><DD CLASS="dd-description">
        Open an Erlang shell in a remote Erlang node.
+</DD><DT CLASS="dt-description"><B><TT>-hidden</TT></B></DT><DD CLASS="dd-description">
+       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 <TT>ctl</TT> or <TT>debug</TT> node.
 </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-->
index 80bc03277ab1d1cc8e0981b399a2a3ec93ef51c6..7c8466eedcb9058a2661a47e46385ae1aa58c648 100644 (file)
@@ -2600,6 +2600,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
@@ -2613,8 +2614,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:
@@ -2648,9 +2657,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}
 
index 32765e08a48ecdf3914dc1e0f873c8a1041f9e9a..955670e33f6e432e7fa834aa554c6fc152a55164 100644 (file)
@@ -57,6 +57,7 @@
 -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_SERVERINFO,   "http://jabber.org/network/serverinfo").
 
 -define(NS_RSM,          "http://jabber.org/protocol/rsm").
 -define(NS_EJABBERD_CONFIG, "ejabberd:config").
index b688427b641364a51a8d60e350e5129aabccbae1..ad9975b15cc1e8132d853f028f3f3d47336b3d7f 100644 (file)
@@ -1,7 +1,7 @@
 %%%----------------------------------------------------------------------
 %%% File    : mod_disco.erl
 %%% Author  : Alexey Shchepin <alexey@process-one.net>
-%%% Purpose : Service Discovery (JEP-0030) support
+%%% Purpose : Service Discovery (XEP-0030) support
 %%% Created :  1 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
 %%%
 %%%
@@ -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,
@@ -79,6 +80,7 @@ start(Host, Opts) ->
     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_info, Host, ?MODULE, get_info, 100),
     ok.
 
 stop(Host) ->
@@ -88,6 +90,7 @@ 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),
+    ejabberd_hooks:delete(disco_info, Host, ?MODULE, get_info, 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),
@@ -153,6 +156,8 @@ process_local_iq_info(From, To, #iq{type = Type, lang = Lang,
                                               Host,
                                               [],
                                               [From, To, Node, Lang]),
+           Info = ejabberd_hooks:run_fold(disco_info, Host, [],
+                                          [Host, ?MODULE, Node, Lang]),
            case ejabberd_hooks:run_fold(disco_local_features,
                                         Host,
                                         empty,
@@ -166,6 +171,7 @@ process_local_iq_info(From, To, #iq{type = Type, lang = Lang,
                          sub_el = [{xmlelement, "query",
                                     [{"xmlns", ?NS_DISCO_INFO} | ANode],
                                     Identity ++ 
+                                    Info ++
                                     lists:map(fun feature_to_xml/1, Features)
                                    }]};
                {error, Error} ->
@@ -362,3 +368,60 @@ get_user_resources(User, Server) ->
                       [{"jid", User ++ "@" ++ Server ++ "/" ++ R},
                        {"name", User}], []}
              end, lists:sort(Rs)).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%% Support for: XEP-0157 Contact Addresses for XMPP Services
+
+get_info(_A, Host, Module, Node, _Lang) when Node == [] ->
+    Serverinfo_fields = get_fields_xml(Host, Module),
+    [{xmlelement, "x",
+      [{"xmlns", ?NS_XDATA}, {"type", "result"}],
+      [{xmlelement, "field",
+       [{"var", "FORM_TYPE"}, {"type", "hidden"}],
+       [{xmlelement, "value",
+         [],
+         [{xmlcdata, ?NS_SERVERINFO}]
+        }]
+       }]
+      ++ Serverinfo_fields
+     }];
+
+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),
+    {xmlelement, "field",
+     [{"var", Var}],
+     Values_xml
+    }.
+
+values_to_xml(Values) ->
+    lists:map(
+      fun(Value) ->
+             {xmlelement, "value",
+              [],
+              [{xmlcdata, Value}]
+             }
+      end,
+      Values
+     ).
index 256b767e8e2b583784d04c8ece1abc4a581cbc1a..f73ebde892c138c393f8cfb565229b0068c0906b 100644 (file)
@@ -214,6 +214,9 @@ do_route1(Host, ServerHost, From, To, Packet) ->
                        #iq{type = get, xmlns = ?NS_DISCO_INFO = XMLNS,
                            sub_el = SubEl, lang = Lang} = IQ ->
                            Node = xml:get_tag_attr_s("node", SubEl),
+                           Info = ejabberd_hooks:run_fold(
+                                    disco_info, ServerHost, [],
+                                    [ServerHost, ?MODULE, "", ""]),
                            case iq_disco(Node, Lang) of
                                [] ->
                                    Res = IQ#iq{type = result,
@@ -227,7 +230,7 @@ do_route1(Host, ServerHost, From, To, Packet) ->
                                    Res = IQ#iq{type = result,
                                                sub_el = [{xmlelement, "query",
                                                           [{"xmlns", XMLNS}],
-                                                          DiscoInfo}]},
+                                                          DiscoInfo ++ Info}]},
                                    ejabberd_router:route(To,
                                                          From,
                                                          jlib:iq_to_xml(Res))
index 2a7242fdfa449f6c6cc50ea8b7e9bb0eab83bc24..69f1983fbcfed50ea5d91d6fbb97ebd2583ded1d 100644 (file)
@@ -353,10 +353,14 @@ do_route1(Host, ServerHost, Access, HistorySize, RoomShaper,
                            case jlib:iq_query_info(Packet) of
                                #iq{type = get, xmlns = ?NS_DISCO_INFO = XMLNS,
                                    sub_el = _SubEl, lang = Lang} = IQ ->
+                                   Info = ejabberd_hooks:run_fold(
+                                            disco_info, ServerHost, [],
+                                            [ServerHost, ?MODULE, "", ""]),
                                    Res = IQ#iq{type = result,
                                                sub_el = [{xmlelement, "query",
                                                           [{"xmlns", XMLNS}],
-                                                          iq_disco_info(Lang)}]},
+                                                          iq_disco_info(Lang)
+                                                          ++Info}]},
                                    ejabberd_router:route(To,
                                                          From,
                                                          jlib:iq_to_xml(Res));
index 901b5261c6973ae026317ae4177cd9d01637952c..c832b1a0d15ee4548be5c74b597fb0b0e3967d01 100644 (file)
@@ -120,9 +120,13 @@ delete_listener(Host) ->
 %%%------------------------
 
 %% disco#info request
-process_iq(_, #iq{type = get, xmlns = ?NS_DISCO_INFO, lang = Lang} = IQ, #state{name=Name}) ->
+process_iq(_, #iq{type = get, xmlns = ?NS_DISCO_INFO, lang = Lang} = IQ,
+          #state{name=Name, serverhost=ServerHost}) ->
+    Info = ejabberd_hooks:run_fold(
+            disco_info, ServerHost, [], [ServerHost, ?MODULE, "", ""]),
     IQ#iq{type = result, sub_el =
-         [{xmlelement, "query", [{"xmlns", ?NS_DISCO_INFO}], iq_disco_info(Lang, Name)}]};
+         [{xmlelement, "query", [{"xmlns", ?NS_DISCO_INFO}],
+           iq_disco_info(Name, Lang) ++ Info}]};
 
 %% disco#items request
 process_iq(_, #iq{type = get, xmlns = ?NS_DISCO_ITEMS} = IQ, _) ->
index e97bf69b96b0db0cc2a3a300ce692d5f85a7556d..58e57150904bca994ffd4c6f20bc632acd7bf23c 100644 (file)
@@ -888,12 +888,15 @@ do_route(ServerHost, Access, Plugins, Host, From, To, Packet) ->
                            sub_el = SubEl, lang = Lang} = IQ ->
                            {xmlelement, _, QAttrs, _} = SubEl,
                            Node = xml:get_attr_s("node", QAttrs),
+                           Info = ejabberd_hooks:run_fold(
+                                    disco_info, ServerHost, [],
+                                    [ServerHost, ?MODULE, "", ""]),
                            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}]});
+                                                            QAttrs, IQRes++Info}]});
                                      {error, Error} ->
                                          jlib:make_error_reply(Packet, Error)
                                  end,
index 7886163b180b43f2d8e3b968d55fd3f3c8f17774..ee109e59805334b6aba5eab211093423f11e8758 100644 (file)
@@ -367,6 +367,9 @@ do_route(ServerHost, From, To, Packet) ->
                                    Packet, ?ERR_NOT_ALLOWED),
                            ejabberd_router:route(To, From, Err);
                        get ->
+                           Info = ejabberd_hooks:run_fold(
+                                    disco_info, ServerHost, [],
+                                    [ServerHost, ?MODULE, "", ""]),
                            ResIQ =
                                IQ#iq{type = result,
                                      sub_el = [{xmlelement,
@@ -384,7 +387,7 @@ do_route(ServerHost, From, To, Packet) ->
                                                   [{"var", ?NS_SEARCH}], []},
                                                  {xmlelement, "feature",
                                                   [{"var", ?NS_VCARD}], []}
-                                                ]
+                                                ] ++ Info
                                                }]},
                            ejabberd_router:route(To,
                                                  From,
index 68faa97dac0aae0a0aa5f432f9a6ef6ee14f31ef..0e854106742634ce9fc88c13060bb6c91ed2010a 100644 (file)
@@ -406,6 +406,7 @@ do_route(State, From, To, Packet) ->
 
 route(State, From, To, Packet) ->
     #jid{user = User, resource = Resource} = To,
+    ServerHost = State#state.serverhost,
     if
        (User /= "") or (Resource /= "") ->
            Err = jlib:make_error_reply(Packet, ?ERR_SERVICE_UNAVAILABLE),
@@ -467,6 +468,9 @@ route(State, From, To, Packet) ->
                                    Packet, ?ERR_NOT_ALLOWED),
                            ejabberd_router:route(To, From, Err);
                        get ->
+                           Info = ejabberd_hooks:run_fold(
+                                    disco_info, ServerHost, [],
+                                    [ServerHost, ?MODULE, "", ""]),
                            ResIQ =
                                IQ#iq{type = result,
                                      sub_el = [{xmlelement,
@@ -482,7 +486,7 @@ route(State, From, To, Packet) ->
                                                   [{"var", ?NS_SEARCH}], []},
                                                  {xmlelement, "feature",
                                                   [{"var", ?NS_VCARD}], []}
-                                                ]
+                                                ] ++ Info
                                                }]},
                            ejabberd_router:route(To,
                                                  From,
index 3f74f71ba0272fe8b712058d469dfc489b246727..44d8eacd64e3a2c36e10ed6cb2eb3767fe31104d 100644 (file)
@@ -344,6 +344,9 @@ do_route(ServerHost, From, To, Packet) ->
                                    Packet, ?ERR_NOT_ALLOWED),
                            ejabberd_router:route(To, From, Err);
                        get ->
+                           Info = ejabberd_hooks:run_fold(
+                                    disco_info, ServerHost, [],
+                                    [ServerHost, ?MODULE, "", ""]),
                            ResIQ =
                                IQ#iq{type = result,
                                      sub_el = [{xmlelement,
@@ -359,7 +362,7 @@ do_route(ServerHost, From, To, Packet) ->
                                                   [{"var", ?NS_SEARCH}], []},
                                                  {xmlelement, "feature",
                                                   [{"var", ?NS_VCARD}], []}
-                                                ]
+                                                ] ++ Info
                                                }]},
                            ejabberd_router:route(To,
                                                  From,