]> granicus.if.org Git - ejabberd/commitdiff
* doc/dev.tex: Developers documentation (not completed)
authorAlexey Shchepin <alexey@process-one.net>
Tue, 11 Nov 2003 20:51:04 +0000 (20:51 +0000)
committerAlexey Shchepin <alexey@process-one.net>
Tue, 11 Nov 2003 20:51:04 +0000 (20:51 +0000)
* 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

SVN Revision: 174

ChangeLog
doc/dev.html [new file with mode: 0644]
doc/dev.tex [new file with mode: 0644]
src/ejabberd_c2s.erl
src/mod_register.erl

index 2eb872bc8981ac27cde8d77177952c1b01d95e3c..ee05be8bbfa606230342ea51d071e3e9111d87d5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+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
@@ -11,7 +20,7 @@
 
        * src/mod_muc/mod_muc_room.erl: Bugfix
 
-       * src/ejabberd_sm.erl (route_message): Bugfix
+       * src/ejabberd_sm.erl (route_message/3): Bugfix
 
 2003-11-09  Alexey Shchepin  <alexey@sevcom.net>
 
diff --git a/doc/dev.html b/doc/dev.html
new file mode 100644 (file)
index 0000000..ad12f39
--- /dev/null
@@ -0,0 +1,364 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
+            "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD><TITLE>Ejabberd Developers Guide</TITLE>
+
+<META http-equiv="Content-Type" content="text/html; charset=ISO8859-1">
+<META name="GENERATOR" content="hevea 1.06">
+</HEAD>
+<BODY >
+<!--HEVEA command line is: /usr/bin/hevea -charset ISO8859-1 dev.tex -->
+<!--HTMLHEAD-->
+<!--ENDHTML-->
+<!--PREFIX <ARG ></ARG>-->
+<!--CUT DEF section 1 -->
+
+
+<H1 ALIGN=center>Ejabberd Developers Guide</H1>
+
+<H3 ALIGN=center>Alexey Shchepin<BR>
+<A HREF="mailto:alexey@sevcom.net"><TT>mailto:alexey@sevcom.net</TT></A><BR>
+<A HREF="xmpp:aleksey@jabber.ru"><TT>xmpp:aleksey@jabber.ru</TT></A></H3>
+
+<H3 ALIGN=center>September 10, 2003</H3><DIV ALIGN=center>
+
+ <IMG SRC="logo.png">
+
+ </DIV><BR>
+<BR>
+
+
+<!--TOC section Table of Contents-->
+
+<H2>Table of Contents</H2><!--SEC END -->
+
+<UL><LI>
+<A HREF="#htoc1">1&nbsp;&nbsp;Introduction</A>
+<UL><LI>
+<A HREF="#htoc2">1.1&nbsp;&nbsp;How it works</A>
+<UL><LI>
+<A HREF="#htoc3">1.1.1&nbsp;&nbsp;Router</A>
+<LI><A HREF="#htoc4">1.1.2&nbsp;&nbsp;Local Router</A>
+<LI><A HREF="#htoc5">1.1.3&nbsp;&nbsp;Session Manager</A>
+<LI><A HREF="#htoc6">1.1.4&nbsp;&nbsp;S2S Manager</A>
+</UL>
+</UL>
+<LI><A HREF="#htoc7">2&nbsp;&nbsp;XML representation</A>
+<LI><A HREF="#htoc8">3&nbsp;&nbsp;Module <TT>xml</TT></A>
+<LI><A HREF="#htoc9">4&nbsp;&nbsp;<TT>ejabberd</TT> modules</A>
+<UL><LI>
+<A HREF="#htoc10">4.1&nbsp;&nbsp;<CODE>gen_mod</CODE> behaviour</A>
+<LI><A HREF="#htoc11">4.2&nbsp;&nbsp;Module <CODE>gen_iq_handler</CODE></A>
+<LI><A HREF="#htoc12">4.3&nbsp;&nbsp;Services</A>
+</UL>
+</UL>
+
+<!--TOC section Introduction-->
+
+<H2><A NAME="htoc1">1</A>&nbsp;&nbsp;Introduction</H2><!--SEC END -->
+
+<A NAME="sec:intro"></A>
+<TT>ejabberd</TT> is a Free and Open Source fault-tolerant distributed Jabber
+server. It is writen mostly in Erlang.<BR>
+<BR>
+The main features of <TT>ejabberd</TT> is:
+<UL><LI>
+Works on most of popular platforms: *nix (tested on Linux and FreeBSD)
+ and Win32
+<LI>Distributed: You can run <TT>ejabberd</TT> on a cluster of machines and all of
+ them will serve one Jabber domain.
+<LI>Fault-tolerance: You can setup an <TT>ejabberd</TT> cluster so that all the
+ information required for a properly working service will be stored
+ permanently on more than one node. This means that if one of the nodes
+ crashes, then the others will continue working without disruption.
+ You can also add or replace more nodes ``on the fly''.
+<LI>Built-in <A HREF="http://www.jabber.org/jeps/jep-0045.html">Multi-User
+ Chat</A> service
+<LI>Built-in IRC transport
+<LI>Built-in
+ <A HREF="http://www.jabber.org/jeps/jep-0060.html">Publish-Subscribe</A>
+ service
+<LI>Built-in Jabber Users Directory service based on users vCards
+<LI>Support for
+ <A HREF="http://www.jabber.org/jeps/jep-0030.html">JEP-0030</A>
+ (Service Discovery).
+<LI>Support for
+ <A HREF="http://www.jabber.org/jeps/jep-0039.html">JEP-0039</A>
+ (Statistics Gathering).
+<LI>Support for <TT>xml:lang</TT> attribute in many XML elements
+</UL>
+<!--TOC subsection How it works-->
+
+<H3><A NAME="htoc2">1.1</A>&nbsp;&nbsp;How it works</H3><!--SEC END -->
+
+<A NAME="sec:howitworks"></A>
+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 have
+the same magic cookie (see Erlang/OTP documentation, in other words the file
+<TT>~ejabberd/.erlang.cookie</TT> must be the same on all nodes). This is
+needed because all nodes exchange information about connected users, S2S
+connections, registered services, etc...<BR>
+<BR>
+Each <TT>ejabberd</TT> node have following modules:
+<UL><LI>
+router;
+<LI>local router.
+<LI>session manager;
+<LI>S2S manager;
+</UL>
+<!--TOC subsubsection Router-->
+
+<H4><A NAME="htoc3">1.1.1</A>&nbsp;&nbsp;Router</H4><!--SEC END -->
+
+This module is the main router of Jabber 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
+searches in global table, and is routed to the appropriate <TT>ejabberd</TT> node or
+process. If it does not exists in either tables, then it sent to the S2S
+manager.<BR>
+<BR>
+<!--TOC subsubsection Local Router-->
+
+<H4><A NAME="htoc4">1.1.2</A>&nbsp;&nbsp;Local Router</H4><!--SEC END -->
+
+This module routes packets which have a destination domain equal to this server
+name. If destination JID has a non-empty user part, then it routed to the
+session manager, else it is processed depending on it's content.<BR>
+<BR>
+<!--TOC subsubsection Session Manager-->
+
+<H4><A NAME="htoc5">1.1.3</A>&nbsp;&nbsp;Session Manager</H4><!--SEC END -->
+
+This module routes packets to local users. It searches for what user resource
+packet must be sended via presence table. If this resource is connected to
+this node, it is routed to C2S process, if it connected via another node, then
+the packet is sent to session manager on that node.<BR>
+<BR>
+<!--TOC subsubsection S2S Manager-->
+
+<H4><A NAME="htoc6">1.1.4</A>&nbsp;&nbsp;S2S Manager</H4><!--SEC END -->
+
+This module routes packets to other Jabber 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
+it is routed to the process that serves this connection, and if a connection
+does not exist, then it is opened and registered.<BR>
+<BR>
+<!--TOC section XML representation-->
+
+<H2><A NAME="htoc7">2</A>&nbsp;&nbsp;XML representation</H2><!--SEC END -->
+
+<A NAME="sec:xmlrepr"></A>
+Each XML stanza represented as following tuple:
+<PRE>
+XMLElement = {xmlelement, Name, Attrs, [ElementOrCDATA]}
+        Name = string()
+        Attrs = [Attr]
+        Attr = {Key, Val}
+        Key = string()
+        Val = string()
+        ElementOrCDATA = XMLElement | CDATA
+        CDATA = {xmlcdata, string()}
+</PRE>E.&nbsp;g. this stanza:
+<PRE>
+&lt;message to='test@conference.e.localhost' type='groupchat'&gt;
+  &lt;body&gt;test&lt;/body&gt;
+&lt;/message&gt;
+</PRE>represented as following structure:
+<PRE>
+{xmlelement, "message",
+    [{"to", "test@conference.e.localhost"},
+     {"type", "groupchat"}],
+    [{xmlelement, "body",
+         [],
+         [{xmlcdata, "test"}]}]}}
+</PRE>
+<!--TOC section Module <TT>xml</TT>-->
+
+<H2><A NAME="htoc8">3</A>&nbsp;&nbsp;Module <TT>xml</TT></H2><!--SEC END -->
+
+<A NAME="sec:xmlmod"></A>
+<DL COMPACT=compact><DT>
+<CODE><B>element_to_string(El) -&gt; string()</B></CODE><DD>
+<PRE>
+El = XMLElement
+</PRE>Returns string representation of XML stanza <TT>El</TT>.<BR>
+<BR>
+<DT><CODE><B>crypt(S) -&gt; string()</B></CODE><DD>
+<PRE>
+S = string()
+</PRE>Returns string which correspond to <TT>S</TT> with encoded XML special
+ characters.<BR>
+<BR>
+<DT><CODE><B>remove_cdata(ECList) -&gt; EList</B></CODE><DD>
+<PRE>
+ECList = [ElementOrCDATA]
+EList = [XMLElement]
+</PRE><TT>EList</TT> is a list of all non-CDATA elements of ECList.<BR>
+<BR>
+<DT><CODE><B>get_path_s(El, Path) -&gt; Res</B></CODE><DD>
+<PRE>
+El = XMLElement
+Path = [PathItem]
+PathItem = PathElem | PathAttr | PathCDATA
+PathElem = {elem, Name}
+PathAttr = {attr, Name}
+PathCDATA = cdata
+Name = string()
+Res = string() | XMLElement
+</PRE>If <TT>Path</TT> is empty, then returns <TT>El</TT>. Else sequentially
+ consider elements of <TT>Path</TT>. Each element is one of:
+ <DL COMPACT=compact><DT>
+ <CODE><B>{elem, Name}</B></CODE><DD> <TT>Name</TT> is name of subelement of
+ <TT>El</TT>, if such element exists, then this element considered in
+ following steps, else returns empty string.
+ <DT><CODE><B>{attr, Name}</B></CODE><DD> If <TT>El</TT> have attribute <TT>Name</TT>, then
+ returns value of this attribute, else returns empty string.
+ <DT><CODE><B>cdata</B></CODE><DD> Returns CDATA of <TT>El</TT>.
+ </DL><BR>
+<BR>
+<DT><B>TODO:</B><DD>
+<PRE>
+         get_cdata/1, get_tag_cdata/1
+         get_attr/2, get_attr_s/2
+         get_tag_attr/2, get_tag_attr_s/2
+         get_subtag/2
+</PRE></DL>
+<!--TOC section <TT>ejabberd</TT> modules-->
+
+<H2><A NAME="htoc9">4</A>&nbsp;&nbsp;<TT>ejabberd</TT> modules</H2><!--SEC END -->
+
+<A NAME="sec:emods"></A>
+<!--TOC subsection <CODE>gen_mod</CODE> behaviour-->
+
+<H3><A NAME="htoc10">4.1</A>&nbsp;&nbsp;<CODE>gen_mod</CODE> behaviour</H3><!--SEC END -->
+
+<A NAME="sec:genmod"></A>
+TBD<BR>
+<BR>
+<!--TOC subsection Module <CODE>gen_iq_handler</CODE>-->
+
+<H3><A NAME="htoc11">4.2</A>&nbsp;&nbsp;Module <CODE>gen_iq_handler</CODE></H3><!--SEC END -->
+
+<A NAME="sec:geniqhandl"></A>
+The module <CODE>gen_iq_handler</CODE> allows to easily write handlers for IQ packets
+of particular XML namespaces that addressed to server or to users bare JIDs.<BR>
+<BR>
+In this module the following functions are defined:
+<DL COMPACT=compact><DT>
+<CODE><B>add_iq_handler(Component, NS, Module, Function, Type)</B></CODE><DD>
+<PRE>
+Component = Module = Function = atom()
+NS = string()
+Type = no_queue | one_queue | parallel
+</PRE>Registers function <CODE>Module:Function</CODE> as handler for IQ packets that
+ contain child of namespace <CODE>NS</CODE> in <CODE>Component</CODE>. Queueing
+ discipline is <CODE>Type</CODE>. There are at least two components defined:
+ <DL COMPACT=compact><DT>
+ <CODE><B>ejabberd_local</B></CODE><DD> Handles packets that addressed to server JID;
+ <DT><CODE><B>ejabberd_sm</B></CODE><DD> Handles packets that addressed to users bare JIDs.
+ </DL>
+<DT><CODE><B>remove_iq_handler(Component, NS)</B></CODE><DD>
+<PRE>
+Component = atom()
+NS = string()
+</PRE>Removes IQ handler for namespace <CODE>NS</CODE> from <CODE>Component</CODE>.
+</DL>
+Handler function must have the following type:
+<DL COMPACT=compact><DT>
+<CODE><B>Module:Function(From, To, IQ)</B></CODE><DD>
+<PRE>
+From = To = jid()
+</PRE></DL>
+<PRE>
+-module(mod_cputime).
+
+-behaviour(gen_mod).
+
+-export([start/1,
+         stop/0,
+         process_local_iq/3]).
+
+-include("ejabberd.hrl").
+-include("jlib.hrl").
+
+-define(NS_CPUTIME, "ejabberd:cputime").
+
+start(Opts) -&gt;
+    IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
+    gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_CPUTIME,
+                                  ?MODULE, process_local_iq, IQDisc).
+
+stop() -&gt;
+    gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_CPUTIME).
+
+process_local_iq(From, To, {iq, ID, Type, XMLNS, SubEl}) -&gt;
+    case Type of
+        set -&gt;
+            {iq, ID, error, XMLNS,
+             [SubEl, ?ERR_NOT_ALLOWED]};
+        get -&gt;
+            CPUTime = element(1, erlang:statistics(runtime))/1000,
+            SCPUTime = lists:flatten(io_lib:format("~.3f", CPUTime)),
+            {iq, ID, result, XMLNS,
+             [{xmlelement, "query",
+               [{"xmlns", ?NS_CPUTIME}],
+               [{xmlelement, "cputime", [], [{xmlcdata, SCPUTime}]}]}]}
+    end.
+</PRE>
+<!--TOC subsection Services-->
+
+<H3><A NAME="htoc12">4.3</A>&nbsp;&nbsp;Services</H3><!--SEC END -->
+
+<A NAME="sec:services"></A>
+TBD<BR>
+<BR>
+TODO: use <CODE>proc_lib</CODE>
+<PRE>
+-module(mod_echo).
+
+-behaviour(gen_mod).
+
+-export([start/1, init/1, stop/0]).
+
+-include("ejabberd.hrl").
+-include("jlib.hrl").
+
+start(Opts) -&gt;
+    Host = gen_mod:get_opt(host, Opts, "echo." ++ ?MYNAME),
+    register(ejabberd_mod_echo, spawn(?MODULE, init, [Host])).
+
+init(Host) -&gt;
+    ejabberd_router:register_local_route(Host),
+    loop(Host).
+
+loop(Host) -&gt;
+    receive
+        {route, From, To, Packet} -&gt;
+            ejabberd_router:route(To, From, Packet),
+            loop(Host);
+        stop -&gt;
+            ejabberd_router:unregister_local_route(Host),
+            ok;
+        _ -&gt;
+            loop(Host)
+    end.
+
+stop() -&gt;
+    ejabberd_mod_echo ! stop,
+    ok.
+</PRE>
+<!--HTMLFOOT-->
+<!--ENDHTML-->
+<!--FOOTER-->
+<HR SIZE=2>
+<BLOCKQUOTE><EM>This document was translated from L<sup>A</sup>T<sub>E</sub>X by
+</EM><A HREF="http://pauillac.inria.fr/~maranget/hevea/index.html"><EM>H<FONT SIZE=2><sup>E</sup></FONT>V<FONT SIZE=2><sup>E</sup></FONT>A</EM></A><EM>.
+</EM></BLOCKQUOTE>
+</BODY>
+</HTML>
diff --git a/doc/dev.tex b/doc/dev.tex
new file mode 100644 (file)
index 0000000..af9340f
--- /dev/null
@@ -0,0 +1,378 @@
+\documentclass[10pt]{article}
+
+\usepackage{graphics}
+\usepackage{hevea}
+\usepackage{verbatim}
+
+
+\newcommand{\logoscale}{0.7}
+\newcommand{\imgscale}{0.58}
+\newcommand{\insimg}[1]{\insscaleimg{\imgscale}{#1}}
+
+\newcommand{\insscaleimg}[2]{
+  \imgsrc{#2}{}
+  \begin{latexonly}
+    \scalebox{#1}{\includegraphics{#2}}
+  \end{latexonly}
+}
+
+\newcommand{\ns}[1]{\texttt{#1}}
+\newcommand{\ejabberd}{\texttt{ejabberd}}
+\newcommand{\Jabber}{Jabber}
+
+\newcommand{\modregister}{\texttt{mod\_register}}
+\newcommand{\modroster}{\texttt{mod\_roster}}
+\newcommand{\modconfigure}{\texttt{mod\_configure}}
+\newcommand{\moddisco}{\texttt{mod\_disco}}
+\newcommand{\modstats}{\texttt{mod\_stats}}
+\newcommand{\modvcard}{\texttt{mod\_vcard}}
+\newcommand{\modoffline}{\texttt{mod\_offline}}
+\newcommand{\modecho}{\texttt{mod\_echo}}
+\newcommand{\modprivate}{\texttt{mod\_private}}
+\newcommand{\modtime}{\texttt{mod\_time}}
+\newcommand{\modversion}{\texttt{mod\_version}}
+c
+%\setcounter{tocdepth}{3}
+
+
+\title{Ejabberd Developers Guide}
+\author{Alexey Shchepin \\
+  \ahrefurl{mailto:alexey@sevcom.net} \\
+  \ahrefurl{xmpp:aleksey@jabber.ru}}
+\date{September 10, 2003}
+
+\begin{document}
+\begin{titlepage}
+  \maketitle{}
+  
+  {\centering
+    \insscaleimg{\logoscale}{logo.png}
+    \par
+  }
+\end{titlepage}
+%\newpage
+\tableofcontents{}
+
+\newpage
+\section{Introduction}
+\label{sec:intro}
+
+\ejabberd{} is a Free and Open Source fault-tolerant distributed \Jabber{}
+server.  It is writen mostly in Erlang.
+
+The main features of \ejabberd{} is:
+\begin{itemize}
+\item Works on most of popular platforms: *nix (tested on Linux and FreeBSD)
+  and Win32
+\item Distributed: You can run \ejabberd{} on a cluster of machines and all of
+  them will serve one Jabber domain.
+\item Fault-tolerance: You can setup an \ejabberd{} cluster so that all the
+  information required for a properly working service will be stored
+  permanently on more than one node.  This means that if one of the nodes
+  crashes, then the others will continue working without disruption.
+  You can also add or replace more nodes ``on the fly''.
+\item Built-in \footahref{http://www.jabber.org/jeps/jep-0045.html}{Multi-User
+    Chat} service
+\item Built-in IRC transport
+\item Built-in
+  \footahref{http://www.jabber.org/jeps/jep-0060.html}{Publish-Subscribe}
+  service
+\item Built-in Jabber Users Directory service based on users vCards
+\item Support for
+  \footahref{http://www.jabber.org/jeps/jep-0030.html}{JEP-0030}
+  (Service Discovery).
+\item Support for
+  \footahref{http://www.jabber.org/jeps/jep-0039.html}{JEP-0039}
+  (Statistics Gathering).
+\item Support for \ns{xml:lang} attribute in many XML elements
+\end{itemize}
+
+
+
+
+
+\subsection{How it works}
+\label{sec:howitworks}
+
+
+
+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 have
+the same magic cookie (see Erlang/OTP documentation, in other words the file
+\texttt{\~{}ejabberd/.erlang.cookie} must be the same on all nodes). This is
+needed because all nodes exchange information about connected users, S2S
+connections, registered services, etc\ldots
+
+
+
+Each \ejabberd{} node have following modules:
+\begin{itemize}
+\item router;
+\item local router.
+\item session manager;
+\item S2S manager;
+\end{itemize}
+
+
+\subsubsection{Router}
+
+This module is the main router of \Jabber{} 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
+searches in global table, and is routed to the appropriate \ejabberd{} node or
+process.  If it does not exists in either tables, then it sent to the S2S
+manager.
+
+
+\subsubsection{Local Router}
+
+This module routes packets which have a destination domain equal to this server
+name.  If destination JID has a non-empty user part, then it routed to the
+session manager, else it is processed depending on it's content.
+
+
+\subsubsection{Session Manager}
+
+This module routes packets to local users.  It searches for what user resource
+packet must be sended via presence table.  If this resource is connected to
+this node, it is routed to C2S process, if it connected via another node, then
+the packet is sent to session manager on that node.
+
+
+\subsubsection{S2S Manager}
+
+This module routes packets to other \Jabber{} 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
+it is routed to the process that serves this connection, and if a connection
+does not exist, then it is opened and registered.
+
+
+
+
+\section{XML representation}
+\label{sec:xmlrepr}
+
+Each XML stanza represented as following tuple:
+\begin{verbatim}
+XMLElement = {xmlelement, Name, Attrs, [ElementOrCDATA]}
+        Name = string()
+        Attrs = [Attr]
+        Attr = {Key, Val}
+        Key = string()
+        Val = string()
+        ElementOrCDATA = XMLElement | CDATA
+        CDATA = {xmlcdata, string()}
+\end{verbatim}
+E.\,g. this stanza:
+\begin{verbatim}
+<message to='test@conference.e.localhost' type='groupchat'>
+  <body>test</body>
+</message>
+\end{verbatim}
+represented as following structure:
+\begin{verbatim}
+{xmlelement, "message",
+    [{"to", "test@conference.e.localhost"},
+     {"type", "groupchat"}],
+    [{xmlelement, "body",
+         [],
+         [{xmlcdata, "test"}]}]}}
+\end{verbatim}
+
+
+
+\section{Module \texttt{xml}}
+\label{sec:xmlmod}
+
+\begin{description}
+\item[\verb|element_to_string(El) -> string()|]
+\begin{verbatim}
+El = XMLElement
+\end{verbatim}
+  Returns string representation of XML stanza \texttt{El}.
+
+\item[\verb|crypt(S) -> string()|]
+\begin{verbatim}
+S = string()
+\end{verbatim}
+  Returns string which correspond to \texttt{S} with encoded XML special
+  characters.
+
+\item[\verb|remove_cdata(ECList) -> EList|]
+\begin{verbatim}
+ECList = [ElementOrCDATA]
+EList = [XMLElement]
+\end{verbatim}
+  \texttt{EList} is a list of all non-CDATA elements of ECList.
+
+
+
+\item[\verb|get_path_s(El, Path) -> Res|]
+\begin{verbatim}
+El = XMLElement
+Path = [PathItem]
+PathItem = PathElem | PathAttr | PathCDATA
+PathElem = {elem, Name}
+PathAttr = {attr, Name}
+PathCDATA = cdata
+Name = string()
+Res = string() | XMLElement
+\end{verbatim}
+  If \texttt{Path} is empty, then returns \texttt{El}.  Else sequentially
+  consider elements of \texttt{Path}.  Each element is one of:
+  \begin{description}
+  \item[\verb|{elem, Name}|] \texttt{Name} is name of subelement of
+    \texttt{El}, if such element exists, then this element considered in
+    following steps, else returns empty string.
+  \item[\verb|{attr, Name}|] If \texttt{El} have attribute \texttt{Name}, then
+    returns value of this attribute, else returns empty string.
+  \item[\verb|cdata|] Returns CDATA of \texttt{El}.
+  \end{description}
+
+\item[TODO:]
+\begin{verbatim}
+         get_cdata/1, get_tag_cdata/1
+         get_attr/2, get_attr_s/2
+         get_tag_attr/2, get_tag_attr_s/2
+         get_subtag/2
+\end{verbatim}
+\end{description}
+
+
+
+
+\section{\ejabberd{} modules}
+\label{sec:emods}
+
+
+\subsection{\verb|gen_mod| behaviour}
+\label{sec:genmod}
+
+TBD
+
+\subsection{Module \verb|gen_iq_handler|}
+\label{sec:geniqhandl}
+
+The module \verb|gen_iq_handler| allows to easily write handlers for IQ packets
+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)|]
+\begin{verbatim}
+Component = Module = Function = atom()
+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:
+  \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)|]
+\begin{verbatim}
+Component = atom()
+NS = string()
+\end{verbatim}
+  Removes IQ handler for namespace \verb|NS| from \verb|Component|.
+\end{description}
+
+Handler function must have the following type:
+\begin{description}
+\item[\verb|Module:Function(From, To, IQ)|]
+\begin{verbatim}
+From = To = jid()
+\end{verbatim}
+\end{description}
+
+
+
+\begin{verbatim}
+-module(mod_cputime).
+
+-behaviour(gen_mod).
+
+-export([start/1,
+         stop/0,
+         process_local_iq/3]).
+
+-include("ejabberd.hrl").
+-include("jlib.hrl").
+
+-define(NS_CPUTIME, "ejabberd:cputime").
+
+start(Opts) ->
+    IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
+    gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_CPUTIME,
+                                  ?MODULE, process_local_iq, IQDisc).
+
+stop() ->
+    gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_CPUTIME).
+
+process_local_iq(From, To, {iq, ID, Type, XMLNS, SubEl}) ->
+    case Type of
+        set ->
+            {iq, ID, error, XMLNS,
+             [SubEl, ?ERR_NOT_ALLOWED]};
+        get ->
+            CPUTime = element(1, erlang:statistics(runtime))/1000,
+            SCPUTime = lists:flatten(io_lib:format("~.3f", CPUTime)),
+            {iq, ID, result, XMLNS,
+             [{xmlelement, "query",
+               [{"xmlns", ?NS_CPUTIME}],
+               [{xmlelement, "cputime", [], [{xmlcdata, SCPUTime}]}]}]}
+    end.
+\end{verbatim}
+
+
+\subsection{Services}
+\label{sec:services}
+
+TBD
+
+
+TODO: use \verb|proc_lib|
+\begin{verbatim}
+-module(mod_echo).
+
+-behaviour(gen_mod).
+
+-export([start/1, init/1, stop/0]).
+
+-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])).
+
+init(Host) ->
+    ejabberd_router:register_local_route(Host),
+    loop(Host).
+
+loop(Host) ->
+    receive
+        {route, From, To, Packet} ->
+            ejabberd_router:route(To, From, Packet),
+            loop(Host);
+        stop ->
+            ejabberd_router:unregister_local_route(Host),
+            ok;
+        _ ->
+            loop(Host)
+    end.
+
+stop() ->
+    ejabberd_mod_echo ! stop,
+    ok.
+\end{verbatim}
+
+
+
+\end{document}
index 433be6c51b1d683419fe38c2fdc7540d134c3937..222436da6ce295211eb72813bbd77ba7ef7542e5 100644 (file)
@@ -255,12 +255,24 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
                            {next_state, wait_for_auth, StateData}
                    end;
                _ ->
-                   ?INFO_MSG("(~w) Forbidden legacy authentification for ~s",
-                             [StateData#state.socket,
-                              jlib:jid_to_string(JID)]),
-                   Err = jlib:make_error_reply(El, ?ERR_NOT_ALLOWED),
-                   send_element(StateData, Err),
-                   {next_state, wait_for_auth, StateData}
+                   if
+                       JID == error ->
+                           ?INFO_MSG(
+                              "(~w) Forbidden legacy authentification for "
+                              "username '~s' with resource '~s'",
+                              [StateData#state.socket, U, R]),
+                           Err = jlib:make_error_reply(El, ?ERR_JID_MALFORMED),
+                           send_element(StateData, Err),
+                           {next_state, wait_for_auth, StateData};
+                       true ->
+                           ?INFO_MSG(
+                              "(~w) Forbidden legacy authentification for ~s",
+                              [StateData#state.socket,
+                               jlib:jid_to_string(JID)]),
+                           Err = jlib:make_error_reply(El, ?ERR_NOT_ALLOWED),
+                           send_element(StateData, Err),
+                           {next_state, wait_for_auth, StateData}
+                   end
            end;
        _ ->
            case jlib:iq_query_info(El) of
index 298464378ad9e76f9456736b49d06a9fafbcb794..62a348d61c2588c37a04ea349b3cb1ac27673156 100644 (file)
@@ -128,6 +128,8 @@ try_register(User, Password) ->
                            ok;
                        {atomic, exists} ->
                            {error, ?ERR_CONFLICT};
+                       {error, invalid_jid} ->
+                           {error, ?ERR_JID_MALFORMED};
                        {error, _Reason} ->
                            {error, ?ERR_INTERNAL_SERVER_ERROR}
                    end