Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 23bf45e881 |
@@ -9,7 +9,8 @@ To compile ejabberd you need:
|
||||
- GNU Make
|
||||
- GCC
|
||||
- Libexpat 1.95 or higher
|
||||
- Erlang/OTP R10B-9 or higher. Recommended versions: R12B-5 and R13B04
|
||||
- Erlang/OTP R10B-9 or higher. The recommended version is R12B-5.
|
||||
Support for R13 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
|
||||
@@ -19,8 +20,8 @@ To compile ejabberd you need:
|
||||
- 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.
|
||||
- ImageMagick's Convert program. Optional. For CAPTCHA challenges.
|
||||
- exmpp 0.9.2 or higher. Optional. For import/export XEP-0227 files.
|
||||
- ImageMagick’s Convert program. Optional. For CAPTCHA challenges.
|
||||
- exmpp 0.9.1 or higher. Optional. For import/export XEP-0227 files.
|
||||
|
||||
|
||||
1. Compile and install on *nix systems
|
||||
|
||||
@@ -97,7 +97,7 @@ extract_lang_all ()
|
||||
done
|
||||
|
||||
cd $MSGS_DIR
|
||||
REVISION=`git describe --always`
|
||||
REVISION=`svn info | grep "^Rev" | head -1 | awk '{print $2}'`
|
||||
zip $HOME/ejabberd-langs-$REVISION.zip *.translate;
|
||||
|
||||
rm *.translate
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ release:
|
||||
@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
|
||||
@read foo
|
||||
@echo "% ejabberd version (automatically generated)." > version.tex
|
||||
@echo "\newcommand{\version}{"`sed '/vsn/!d;s/\(.*\)"\(.*\)"\(.*\)/\2/' ../src/ejabberd.app`"}" >> version.tex
|
||||
@echo -n "% Contributed modules (automatically generated)." > contributed_modules.tex
|
||||
|
||||
+2
-5
@@ -2,7 +2,7 @@
|
||||
"http://www.w3.org/TR/REC-html40/loose.dtd">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Ejabberd 2.1.4 Developers Guide
|
||||
<TITLE>Ejabberd 2.1.0 Developers Guide
|
||||
</TITLE>
|
||||
|
||||
<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
|
||||
@@ -49,7 +49,7 @@ TD P{margin:0px;}
|
||||
<!--HEVEA command line is: /usr/bin/hevea -fix -pedantic dev.tex -->
|
||||
<!--CUT DEF section 1 --><P><A NAME="titlepage"></A>
|
||||
|
||||
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.4 Developers Guide</H1><H3 CLASS="titlerest">Alexey Shchepin<BR>
|
||||
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.0 Developers Guide</H1><H3 CLASS="titlerest">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></TD></TR>
|
||||
</TABLE><DIV CLASS="center">
|
||||
@@ -194,9 +194,6 @@ operation are as follows:
|
||||
auth:User:Server:Password (check if a username/password pair is correct)
|
||||
</LI><LI CLASS="li-itemize">isuser:User:Server (check if it’s a valid user)
|
||||
</LI><LI CLASS="li-itemize">setpass:User:Server:Password (set user’s password)
|
||||
</LI><LI CLASS="li-itemize">tryregister:User:Server:Password (try to register an account)
|
||||
</LI><LI CLASS="li-itemize">removeuser:User:Server (remove this account)
|
||||
</LI><LI CLASS="li-itemize">removeuser3:User:Server:Password (remove this account if the password is correct)
|
||||
</LI></UL>
|
||||
</LI></UL>
|
||||
</LI><LI CLASS="li-itemize">write to stdout: AABB
|
||||
|
||||
@@ -176,9 +176,6 @@ That script is supposed to do theses actions, in an infinite loop:
|
||||
\item auth:User:Server:Password (check if a username/password pair is correct)
|
||||
\item isuser:User:Server (check if it's a valid user)
|
||||
\item setpass:User:Server:Password (set user's password)
|
||||
\item tryregister:User:Server:Password (try to register an account)
|
||||
\item removeuser:User:Server (remove this account)
|
||||
\item removeuser3:User:Server:Password (remove this account if the password is correct)
|
||||
\end{itemize}
|
||||
\end{itemize}
|
||||
\item write to stdout: AABB
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
"http://www.w3.org/TR/REC-html40/loose.dtd">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Ejabberd 2.1.4 Feature Sheet
|
||||
<TITLE>Ejabberd 2.1.0 Feature Sheet
|
||||
</TITLE>
|
||||
|
||||
<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
|
||||
@@ -50,7 +50,7 @@ SPAN{width:20%; float:right; text-align:left; margin-left:auto;}
|
||||
<!--HEVEA command line is: /usr/bin/hevea -fix -pedantic features.tex -->
|
||||
<!--CUT DEF section 1 --><P><A NAME="titlepage"></A>
|
||||
|
||||
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.4 Feature Sheet</H1><H3 CLASS="titlerest">Sander Devrieze<BR>
|
||||
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.0 Feature Sheet</H1><H3 CLASS="titlerest">Sander Devrieze<BR>
|
||||
<A HREF="mailto:s.devrieze@pandora.be"><TT>mailto:s.devrieze@pandora.be</TT></A><BR>
|
||||
<A HREF="xmpp:sander@devrieze.dyndns.org"><TT>xmpp:sander@devrieze.dyndns.org</TT></A></H3></TD></TR>
|
||||
</TABLE><DIV CLASS="center">
|
||||
|
||||
+258
-384
File diff suppressed because it is too large
Load Diff
+92
-237
@@ -92,13 +92,11 @@
|
||||
\newcommand{\modrosterodbc}{\module{mod\_roster\_odbc}}
|
||||
\newcommand{\modservicelog}{\module{mod\_service\_log}}
|
||||
\newcommand{\modsharedroster}{\module{mod\_shared\_roster}}
|
||||
\newcommand{\modsic}{\module{mod\_sic}}
|
||||
\newcommand{\modstats}{\module{mod\_stats}}
|
||||
\newcommand{\modtime}{\module{mod\_time}}
|
||||
\newcommand{\modvcard}{\module{mod\_vcard}}
|
||||
\newcommand{\modvcardldap}{\module{mod\_vcard\_ldap}}
|
||||
\newcommand{\modvcardodbc}{\module{mod\_vcard\_odbc}}
|
||||
\newcommand{\modvcardxupdate}{\module{mod\_vcard\_xupdate}}
|
||||
\newcommand{\modversion}{\module{mod\_version}}
|
||||
|
||||
%% Contributed modules
|
||||
@@ -310,7 +308,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. The recommended versions are R12B-5 and R13B04.
|
||||
\item Erlang/OTP R10B-9 or higher. The recommended version is R12B-5. Support for R13 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}.
|
||||
@@ -318,7 +316,7 @@ To compile \ejabberd{} on a `Unix-like' operating system, you need:
|
||||
\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}.
|
||||
\item exmpp 0.9.2 or higher. Optional. For import/export user data with \xepref{0227} XML files.
|
||||
\item exmpp 0.9.1 or higher. Optional. For import/export user data with \xepref{0227} XML files.
|
||||
\end{itemize}
|
||||
|
||||
\makesubsection{download}{Download Source Code}
|
||||
@@ -327,12 +325,10 @@ To compile \ejabberd{} on a `Unix-like' operating system, you need:
|
||||
Released versions of \ejabberd{} are available in the ProcessOne \ejabberd{} downloads page:
|
||||
\ahrefurl{http://www.process-one.net/en/ejabberd/downloads}
|
||||
|
||||
\ind{Git repository}
|
||||
Alternatively, the latest development source code can be retrieved from the Git repository using the commands:
|
||||
\ind{Subversion repository}
|
||||
Alternatively, the latest development version can be retrieved from the Subversion repository using this command:
|
||||
\begin{verbatim}
|
||||
git clone git://git.process-one.net/ejabberd/mainline.git ejabberd
|
||||
cd ejabberd
|
||||
git checkout -b 2.1.x origin/2.1.x
|
||||
svn co http://svn.process-one.net/ejabberd/trunk ejabberd
|
||||
\end{verbatim}
|
||||
|
||||
|
||||
@@ -384,6 +380,21 @@ 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}
|
||||
|
||||
@@ -798,18 +809,18 @@ 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{max\_fsm\_queue},
|
||||
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{max\_stanza\_size}, \texttt{shaper}
|
||||
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{max\_fsm\_queue},
|
||||
\texttt{service\_check\_from}, \texttt{shaper}
|
||||
\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}.\\
|
||||
@@ -833,10 +844,13 @@ This is a detailed description of each option allowed by the listening modules:
|
||||
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{captcha} \ind{options!http-captcha}
|
||||
Simple web page that allows a user to fill a CAPTCHA challenge (see section \ref{captcha}).
|
||||
\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}
|
||||
This option can be used with \term{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 \term{true} or
|
||||
\term{false}. The default value is \term{true} which conforms to \xepref{0114}.
|
||||
\titem{\{hosts, [Hostname, ...], [HostOption, ...]\}} \ind{options!hosts}
|
||||
The external Jabber component that connects to this \term{ejabberd\_service}
|
||||
can serve one or more hostnames.
|
||||
@@ -846,6 +860,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 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
|
||||
@@ -878,27 +894,17 @@ This is a detailed description of each option allowed by the listening modules:
|
||||
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
|
||||
(Finite State Machine).
|
||||
Roughly speaking, each message in such queues represents one XML
|
||||
stanza queued to be sent into its relevant outgoing stream. If queue size
|
||||
reaches the limit (because, for example, the receiver of stanzas is too slow),
|
||||
the FSM and the corresponding connection (if any) will be terminated
|
||||
and error message will be logged.
|
||||
The reasonable value for this option depends on your hardware configuration.
|
||||
However, there is no much sense to set the size above 1000 elements.
|
||||
This option can be specified for \term{ejabberd\_service} and
|
||||
\term{ejabberd\_c2s} listeners,
|
||||
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 \term{ejabberd\_service} or
|
||||
\term{ejabberd\_c2s} listeners,
|
||||
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,
|
||||
because it is calculated with the precision of one block of read
|
||||
because it is calculated with the precision of one block of readed
|
||||
data. For example \verb|{max_stanza_size, 65536}|. The default
|
||||
value is \term{infinity}. Recommended values are 65536 for c2s
|
||||
connections and 131072 for s2s connections. s2s max stanza size
|
||||
@@ -910,13 +916,10 @@ This is a detailed description of each option allowed by the listening modules:
|
||||
and you also want \term{mod\_http\_bind} to serve the URIs \term{/http-bind/},
|
||||
use this option: \term{\{request\_handlers, [\{["a", "b"], mod\_foo\}, \{["http-bind"], mod\_http\_bind\}]\}}
|
||||
\titem{\{service\_check\_from, true|false\}}
|
||||
\ind{options!service\_check\_from}
|
||||
This option can be used with \term{ejabberd\_service} only.
|
||||
\xepref{0114} requires that the domain must match the hostname of the component.
|
||||
If this option is set to \term{false}, \ejabberd{} will allow the component
|
||||
to send stanzas with any arbitrary domain in the 'from' attribute.
|
||||
Only use this option if you are completely sure about it.
|
||||
The default value is \term{true}, to be compliant with \xepref{0114}.
|
||||
By enabling this option, \ejabberd{} allows the component to send packets with any arbitrary domain in the 'from' attribute.
|
||||
Note that \xepref{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.
|
||||
\titem{\{shaper, none|ShaperName\}} \ind{options!shaper}This option defines a
|
||||
shaper for the port (see section~\ref{shapers}). The default value
|
||||
is \term{none}.
|
||||
@@ -935,10 +938,9 @@ 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://xmpp.org/rfcs/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.
|
||||
The option \term{tls} can also be used in \term{ejabberd\_http} to support HTTPS.
|
||||
\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
|
||||
@@ -977,28 +979,13 @@ There are some additional global options that can be specified in the ejabberd c
|
||||
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
|
||||
(Finite State Machine).
|
||||
Roughly speaking, each message in such queues represents one XML
|
||||
stanza queued to be sent into its relevant outgoing stream. If queue size
|
||||
reaches the limit (because, for example, the receiver of stanzas is too slow),
|
||||
the FSM and the corresponding connection (if any) will be terminated
|
||||
and error message will be logged.
|
||||
The reasonable value for this option depends on your hardware configuration.
|
||||
However, there is no much sense to set the size above 1000 elements.
|
||||
This option can be specified for \term{ejabberd\_service} and
|
||||
\term{ejabberd\_c2s} listeners,
|
||||
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 \term{ejabberd\_service} or
|
||||
\term{ejabberd\_c2s} listeners,
|
||||
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{\{route\_subdomains, local|s2s\}}
|
||||
Defines if ejabberd must route stanzas directed to subdomains locally (compliant with
|
||||
\footahref{http://xmpp.org/rfcs/rfc3920.html\#rules.subdomain}{RFC 3920: XMPP Core}),
|
||||
or to foreign server using S2S (compliant with
|
||||
\footahref{http://tools.ietf.org/html/draft-saintandre-rfc3920bis-09\#section-11.3}{RFC 3920 bis}).
|
||||
\end{description}
|
||||
|
||||
\makesubsubsection{listened-examples}{Examples}
|
||||
@@ -1187,7 +1174,8 @@ for user authentication. The syntax is:
|
||||
The following authentication methods are supported by \ejabberd{}:
|
||||
\begin{itemize}
|
||||
\item internal (default) --- See section~\ref{internalauth}.
|
||||
\item external --- See section~\ref{extauth}.
|
||||
\item external --- There are \footahref{http://www.ejabberd.im/extauth}{some
|
||||
example authentication scripts}.
|
||||
\item ldap --- See section~\ref{ldap}.
|
||||
\item odbc --- See section~\ref{mysql}, \ref{pgsql},
|
||||
\ref{mssql} and \ref{odbc}.
|
||||
@@ -1195,7 +1183,7 @@ The following authentication methods are supported by \ejabberd{}:
|
||||
\item pam --- See section~\ref{pam}.
|
||||
\end{itemize}
|
||||
|
||||
Account creation is only supported by internal, external and odbc methods.
|
||||
Account creation is only supported by internal and odbc methods.
|
||||
|
||||
\makesubsubsection{internalauth}{Internal}
|
||||
\ind{internal authentication}\ind{Mnesia}
|
||||
@@ -1217,42 +1205,6 @@ Examples:
|
||||
\end{verbatim}
|
||||
\end{itemize}
|
||||
|
||||
\makesubsubsection{extauth}{External Script}
|
||||
\ind{external authentication}
|
||||
|
||||
In this authentication method, when \ejabberd{} starts,
|
||||
it start a script, and calls it to perform authentication tasks.
|
||||
|
||||
The server administrator can write the external authentication script
|
||||
in any language.
|
||||
The details on the interface between ejabberd and the script are described
|
||||
in the \term{ejabberd Developers Guide}.
|
||||
There are also \footahref{http://www.ejabberd.im/extauth}{several example authentication scripts}.
|
||||
|
||||
These are the specific options:
|
||||
\begin{description}
|
||||
\titem{\{extauth\_program, PathToScript\}}
|
||||
Indicate in this option the full path to the external authentication script.
|
||||
The script must be executable by ejabberd.
|
||||
|
||||
\titem{\{extauth\_cache, false|CacheTimeInteger\}}
|
||||
The value \term{false} disables the caching feature, this is the default.
|
||||
The integer \term{0} (zero) enables caching for statistics, but doesn't use that cached information to authenticate users.
|
||||
If another integer value is set, caching is enabled both for statistics and for authentication:
|
||||
the CacheTimeInteger indicates the number of seconds that ejabberd can reuse
|
||||
the authentication information since the user last disconnected,
|
||||
to verify again the user authentication without querying again the extauth script.
|
||||
Note: caching should not be enabled in a host if internal auth is also enabled.
|
||||
If caching is enabled, \term{mod\_last} or \term{mod\_last\_odbc} must be enabled also in that vhost.
|
||||
\end{description}
|
||||
|
||||
This example sets external authentication, the extauth script, and enables caching for 10 minutes:
|
||||
\begin{verbatim}
|
||||
{auth_method, [external]}.
|
||||
{extauth_program, "/etc/ejabberd/JabberAuth.class.php"}.
|
||||
{extauth_cache, 600}.
|
||||
\end{verbatim}
|
||||
|
||||
\makesubsubsection{saslanonymous}{SASL Anonymous and Anonymous Login}
|
||||
\ind{sasl anonymous}\ind{anonymous login}
|
||||
|
||||
@@ -1333,10 +1285,6 @@ Options:
|
||||
\titem{\{pam\_service, Name\}}\ind{options!pam\_service}This option defines the PAM service name.
|
||||
Default is \term{"ejabberd"}. Refer to the PAM documentation of your operation system
|
||||
for more information.
|
||||
\titem{\{pam\_userinfotype, username|jid\}}\ind{options!pam\_userinfotype}
|
||||
This option defines what type of information about the user ejabberd
|
||||
provides to the PAM service: only the username, or the user JID.
|
||||
Default is \term{username}.
|
||||
\end{description}
|
||||
|
||||
Example:
|
||||
@@ -1490,11 +1438,6 @@ second elements of the tuples in the list. If it matches, the first element of
|
||||
the first matched tuple is returned, otherwise the value `\term{deny}' is
|
||||
returned.
|
||||
|
||||
If you define specific Access rights in a virtual host,
|
||||
remember that the globally defined Access rights have precedence over those.
|
||||
This means that, in case of conflict, the Access granted or denied in the global server is used
|
||||
and the Access of a virtual host doesn't have effect.
|
||||
|
||||
Example:
|
||||
\begin{verbatim}
|
||||
{access, configure, [{allow, admin}]}.
|
||||
@@ -1531,7 +1474,7 @@ This example limits the number of sessions per user to 5 for all users, and to 1
|
||||
\ind{options!max\_s2s\_connections}
|
||||
|
||||
The special access \term{max\_s2s\_connections} specifies how many
|
||||
simultaneous S2S connections can be established to a specific remote XMPP 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}.
|
||||
|
||||
@@ -1990,9 +1933,19 @@ enabled. This can be done, by using next commands:
|
||||
\makesubsubsection{configuremssql}{Database Connection}
|
||||
\ind{Microsoft SQL Server!Database Connection}
|
||||
|
||||
The configuration of Database Connection for a Microsoft SQL Server
|
||||
is the same as the configuration for
|
||||
ODBC compatible servers (see section~\ref{configureodbc}).
|
||||
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{mssqlauth}{Authentication}
|
||||
@@ -2000,8 +1953,7 @@ ODBC compatible servers (see section~\ref{configureodbc}).
|
||||
|
||||
%TODO: not sure if this section is right!!!!!!
|
||||
|
||||
The configuration of Authentication for a Microsoft SQL Server
|
||||
is the same as the configuration for
|
||||
The configuration of Microsoft SQL Server is the same as the configuration of
|
||||
ODBC compatible servers (see section~\ref{odbcauth}).
|
||||
|
||||
\makesubsubsection{mssqlstorage}{Storage}
|
||||
@@ -2198,12 +2150,9 @@ module loaded!
|
||||
server and use LDAP directory as vCard storage. Shared rosters are not supported
|
||||
yet.
|
||||
|
||||
Usually \ejabberd{} treats LDAP as a read-only storage:
|
||||
Note that \ejabberd{} treats LDAP as a read-only storage:
|
||||
it is possible to consult data, but not possible to
|
||||
create accounts or edit vCard that is stored in LDAP.
|
||||
However, it is possible to change passwords if \module{mod\_register} module is enabled
|
||||
and LDAP server supports
|
||||
\footahref{http://tools.ietf.org/html/rfc3062}{RFC 3062}.
|
||||
create accounts, change password or edit vCard that is stored in LDAP.
|
||||
|
||||
|
||||
\makesubsubsection{ldapconnection}{Connection}
|
||||
@@ -2217,11 +2166,6 @@ Allowed values are: \term{none}, \term{tls}.
|
||||
The value \term{tls} enables encryption by using LDAP over SSL.
|
||||
Note that STARTTLS encryption is not supported.
|
||||
The default value is: \term{none}.
|
||||
\titem{\{ldap\_tls\_verify, false|soft|hard\}} \ind{options!ldap\_tls\_verify}
|
||||
This option specifies whether to verify LDAP server certificate or not when TLS is enabled.
|
||||
When \term{hard} is enabled \ejabberd{} doesn't proceed if a certificate is invalid.
|
||||
When \term{soft} is enabled \ejabberd{} proceeds even if check fails.
|
||||
The default is \term{false} which means no checks are performed.
|
||||
\titem{\{ldap\_port, Number\}} \ind{options!ldap\_port}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.
|
||||
@@ -2242,7 +2186,8 @@ Example:
|
||||
{ldap_password, "secret"}.
|
||||
\end{verbatim}
|
||||
|
||||
Note that current LDAP implementation does not support SASL authentication.
|
||||
Note that current LDAP implementation does not support SSL secured communication
|
||||
and SASL authentication.
|
||||
|
||||
\makesubsubsection{ldapauth}{Authentication}
|
||||
|
||||
@@ -2271,27 +2216,12 @@ You can authenticate users against an LDAP directory. Available options are:
|
||||
\titem{\{ldap\_filter, 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 Filter value is: \term{undefined}. Example:
|
||||
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
|
||||
\emph{must not} use \option{ldap\_uidattr} attribute in filter because this
|
||||
attribute will be substituted in LDAP filter automatically.
|
||||
\titem{\{ldap\_dn\_filter, \{ Filter, FilterAttrs \}\}}\ind{options!ldap\_dn\_filter}
|
||||
This filter is applied on the results returned by the main filter. This filter
|
||||
performs additional LDAP lookup to make the complete result. This is useful
|
||||
when you are unable to define all filter rules in \term{ldap\_filter}. You
|
||||
can define \term{"\%u"}, \term{"\%d"}, \term{"\%s"} and \term{"\%D"} pattern
|
||||
variables in Filter: \term{"\%u"} is replaced by a user's part of a JID,
|
||||
\term{"\%d"} is replaced by the corresponding domain (virtual host),
|
||||
all \term{"\%s"} variables are consecutively replaced by values of FilterAttrs
|
||||
attributes and \term{"\%D"} is replaced by Distinguished Name. By default
|
||||
\term{ldap\_dn\_filter} is undefined.
|
||||
Example:
|
||||
\begin{verbatim}
|
||||
{ldap_dn_filter, {"(&(name=%s)(owner=%D)(user=%u@%d))", ["sn"]}}.
|
||||
\end{verbatim}
|
||||
Since this filter makes additional LDAP lookups, use it only in the
|
||||
last resort: try to define all filter rules in \term{ldap\_filter} if possible.
|
||||
|
||||
\titem{\{ldap\_local\_filter, Filter\}}\ind{options!ldap\_local\_filter}
|
||||
If you can't use \term{ldap\_filter} due to performance reasons
|
||||
(the LDAP server has many users registered),
|
||||
@@ -2518,13 +2448,11 @@ The following table lists all modules included in \ejabberd{}.
|
||||
\hline \ahrefloc{modservicelog}{\modservicelog{}} & Copy user messages to logger service & \\
|
||||
\hline \ahrefloc{modsharedroster}{\modsharedroster{}} & Shared roster management & \modroster{} or \\
|
||||
& & \modrosterodbc\\
|
||||
\hline \ahrefloc{modsic}{\modsic{}} & Server IP Check (\xepref{0279}) & \\
|
||||
\hline \ahrefloc{modstats}{\modstats{}} & Statistics Gathering (\xepref{0039}) & \\
|
||||
\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 (*) \\
|
||||
\hline \ahrefloc{modvcardxupdate}{\modvcardxupdate{}} & vCard-Based Avatars (\xepref{0153}) & \modvcard{} or \modvcardodbc{} \\
|
||||
\hline \ahrefloc{modversion}{\modversion{}} & Software Version (\xepref{0092}) & \\
|
||||
\hline
|
||||
\end{tabular}
|
||||
@@ -2926,11 +2854,12 @@ 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{\{custom\_headers, [ \{Name, Value\}, ...]\}} \ind{options!customheaders}
|
||||
Indicate custom HTTP headers to be included in all responses.
|
||||
Default value is: \term{[]}
|
||||
\titem{\{content\_types, [ \{Name, Type\}, ...]\}} \ind{options!contenttypes}
|
||||
Specify mappings of extension to content type.
|
||||
%B \titem{content\_types} \ind{options!contenttypes}
|
||||
%M \titem{\{content\_types, \{Extension, Type\} \}} \ind{options!contenttypes}
|
||||
%B \titem{\{content\_types, [ Extension, Type, ... ]\}} \ind{options!contenttypes}
|
||||
%B \titem{\{content\_types, [ {Extension, Type}, ... ]\}} \ind{options!contenttypes}
|
||||
%M \titem{\{content\_types, [ \{Extension, Type\}, ... ]\}} \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'.
|
||||
@@ -2953,9 +2882,6 @@ To use this module you must enable it:
|
||||
{docroot, "/var/www"},
|
||||
{accesslog, "/var/log/ejabberd/access.log"},
|
||||
{directory_indices, ["index.html", "main.htm"]},
|
||||
{custom_headers, [{"X-Powered-By", "Erlang/OTP"},
|
||||
{"X-Fry", "It's a widely-believed fact!"}
|
||||
]},
|
||||
{content_types, [{".ogg", "audio/ogg"},
|
||||
{".png", "image/png"},
|
||||
{".jpg", undefined}
|
||||
@@ -3454,7 +3380,7 @@ online again. Thus it is very similar to how email works. Note that
|
||||
(see section~\ref{ejabberdctl}).
|
||||
|
||||
\begin{description}
|
||||
\titem{\{access\_max\_user\_messages, AccessName\}}\ind{options!access\_max\_user\_messages}
|
||||
\titem{\{access\_max\_user\_messages, Number\}}\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,
|
||||
@@ -3545,7 +3471,7 @@ their \XMPP{} 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://xmpp.org/rfcs/rfc3921.html\#privacy})
|
||||
(from \ahrefurl{http://xmpp.org/specs/rfc3921.html\#privacy})
|
||||
\end{quote}
|
||||
|
||||
Options:
|
||||
@@ -3586,12 +3512,6 @@ to listen for. Default is an IP address of the service's DNS name, or,
|
||||
if fails, \verb|{127,0,0,1}|.
|
||||
\titem{\{port, Number\}}\ind{options!port}This option defines port to listen for
|
||||
incoming connections. Default is~7777.
|
||||
\titem{\{hostname, HostName\}}\ind{options!hostname}Defines a hostname advertised
|
||||
by the service when establishing a session with clients. This is useful when
|
||||
you run the service behind a NAT. The default is the value of \term{ip} option.
|
||||
Examples: \term{"proxy.mydomain.org"}, \term{"200.150.100.50"}. Note that
|
||||
not all clients understand domain names in stream negotiation,
|
||||
so you should think twice before setting domain name in this option.
|
||||
\titem{\{auth\_type, anonymous|plain\}}\ind{options!auth\_type}SOCKS5 authentication type.
|
||||
Possible values are \term{anonymous} and \term{plain}. Default is
|
||||
\term{anonymous}.
|
||||
@@ -3651,8 +3571,6 @@ and it requires \modcaps{}.
|
||||
Options:
|
||||
\begin{description}
|
||||
\hostitem{pubsub}
|
||||
If you use \modpubsubodbc, please ensure the prefix contains only one dot,
|
||||
for example `\jid{pubsub.}', or `\jid{publish.}',.
|
||||
\titem{\{access\_createnode, AccessName\}} \ind{options!access\_createnode}
|
||||
This option restricts which users are allowed to create pubsub nodes using
|
||||
ACL and ACCESS.
|
||||
@@ -3749,10 +3667,6 @@ Options:
|
||||
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).
|
||||
\titem{\{access\_from, AccessName\}} \ind{options!access\_from}By default, \ejabberd{}
|
||||
doesn't allow to register new accounts from s2s or existing c2s sessions. You can
|
||||
change it by defining access rule in this option. Use with care: allowing registration
|
||||
from s2s leads to uncontrolled massive accounts creation by rogue users.
|
||||
\titem{\{welcome\_message, 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.
|
||||
@@ -3836,7 +3750,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://xmpp.org/rfcs/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:
|
||||
@@ -4014,17 +3928,6 @@ Examples:
|
||||
\end{table}
|
||||
\end{itemize}
|
||||
|
||||
\makesubsection{modsic}{\modsic{}}
|
||||
\ind{modules!\modstats{}}\ind{protocols!XEP-0279: Server IP Check}
|
||||
|
||||
This module adds support for Server IP Check (\xepref{0279}). This protocol
|
||||
enables a client to discover its external IP address.
|
||||
|
||||
Options:
|
||||
\begin{description}
|
||||
\iqdiscitem{\ns{urn:xmpp:sic:0}}
|
||||
\end{description}
|
||||
|
||||
\makesubsection{modstats}{\modstats{}}
|
||||
\ind{modules!\modstats{}}\ind{protocols!XEP-0039: Statistics Gathering}\ind{statistics}
|
||||
|
||||
@@ -4147,12 +4050,9 @@ Examples:
|
||||
implemented in the \modvcardldap{} module. This module does not depend on the
|
||||
authentication method (see~\ref{ldapauth}).
|
||||
|
||||
Usually \ejabberd{} treats LDAP as a read-only storage:
|
||||
Note that \ejabberd{} treats LDAP as a read-only storage:
|
||||
it is possible to consult data, but not possible to
|
||||
create accounts or edit vCard that is stored in LDAP.
|
||||
However, it is possible to change passwords if \module{mod\_register} module is enabled
|
||||
and LDAP server supports
|
||||
\footahref{http://tools.ietf.org/html/rfc3062}{RFC 3062}.
|
||||
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
|
||||
@@ -4356,27 +4256,6 @@ searching his info in LDAP.
|
||||
\end{verbatim}
|
||||
\end{itemize}
|
||||
|
||||
\makesubsection{modvcardxupdate}{\modvcardxupdate{}}
|
||||
\ind{modules!\modvcardxupdate{}}\ind{protocols!XEP-0153: vCard-Based Avatars}
|
||||
|
||||
The user's client can store an avatar in the user vCard.
|
||||
The vCard-Based Avatars protocol (\xepref{0153})
|
||||
provides a method for clients to inform the contacts what is the avatar hash value.
|
||||
However, simple or small clients may not implement that protocol.
|
||||
|
||||
If this module is enabled, all the outgoing client presence stanzas get automatically
|
||||
the avatar hash on behalf of the client.
|
||||
So, the contacts receive the presence stanzas with the Update Data described
|
||||
in \xepref{0153} as if the client would had inserted it itself.
|
||||
If the client had already included such element in the presence stanza,
|
||||
it is replaced with the element generated by ejabberd.
|
||||
|
||||
By enabling this module, each vCard modification produces a hash recalculation,
|
||||
and each presence sent by a client produces hash retrieval and a
|
||||
presence stanza rewrite.
|
||||
For this reason, enabling this module will introduce a computational overhead
|
||||
in servers with clients that change frequently their presence.
|
||||
|
||||
\makesubsection{modversion}{\modversion{}}
|
||||
\ind{modules!\modversion{}}\ind{protocols!XEP-0092: Software Version}
|
||||
|
||||
@@ -4511,7 +4390,7 @@ The command line parameters:
|
||||
\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"'}
|
||||
\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}
|
||||
@@ -4526,7 +4405,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/"'}
|
||||
\titem{-mnesia dir "/var/lib/ejabberd/"}
|
||||
Specify the Mnesia database directory.
|
||||
\titem{-sasl sasl\_error\_logger \{file, "/var/log/ejabberd/erlang.log"\}}
|
||||
Path to the Erlang/OTP system log file.
|
||||
@@ -4588,13 +4467,11 @@ The most 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 consume a lot of memory if you have a large database,
|
||||
so better use \term{install\_fallback}.
|
||||
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.
|
||||
This means that, after running this command, you have to restart ejabberd.
|
||||
This command requires less memory than \term{restore}.
|
||||
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}
|
||||
@@ -4608,7 +4485,8 @@ The most interesting ones are:
|
||||
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/MESSENGER/ejabberd+migration+kit}{ejabberd migration kit}.
|
||||
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.
|
||||
@@ -4640,8 +4518,9 @@ ArgumentValue = any()
|
||||
\end{verbatim}
|
||||
|
||||
The default value is to not define any restriction: \term{[]}.
|
||||
The authentication information is provided when executing a command,
|
||||
and is Username, Hostname and Password of a local XMPP account
|
||||
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 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.
|
||||
@@ -4708,10 +4587,7 @@ Here you can edit access restrictions, manage users, create backups,
|
||||
manage the database, enable/disable ports listened for, view server
|
||||
statistics,\ldots
|
||||
|
||||
The access rule \term{configure} determines what accounts can access the Web Admin and modify it.
|
||||
The access rule \term{webadmin\_view} is to grant only view access: those accounts can browse the Web Admin with read-only access.
|
||||
|
||||
Example configurations:
|
||||
Examples:
|
||||
\begin{itemize}
|
||||
\item You can serve the Web Admin on the same port as the
|
||||
\ind{protocols!XEP-0025: HTTP Polling}HTTP Polling interface. In this example
|
||||
@@ -4725,14 +4601,10 @@ Example configurations:
|
||||
URL). If you log in with `\jid{admin@example.com}' on \\
|
||||
\verb|http://example.org:5280/admin/server/example.com/| you can only
|
||||
administer the virtual host \jid{example.com}.
|
||||
The account `\jid{reviewer@example.com}' can browse that vhost in read-only mode.
|
||||
\begin{verbatim}
|
||||
{acl, admins, {user, "admin", "example.net"}}.
|
||||
{host_config, "example.com", [{acl, admins, {user, "admin", "example.com"}}]}.
|
||||
{host_config, "example.com", [{acl, viewers, {user, "reviewer", "example.com"}}]}.
|
||||
|
||||
{access, configure, [{allow, admins}]}.
|
||||
{access, webadmin_view, [{allow, viewers}]}.
|
||||
|
||||
{hosts, ["example.org"]}.
|
||||
|
||||
@@ -4848,26 +4720,9 @@ ejabberdctl start
|
||||
ejabberdctl mnesia_change_nodename $OLDNODE $NEWNODE $OLDFILE $NEWFILE
|
||||
\end{verbatim}
|
||||
|
||||
\item Install the backup file as a fallback:
|
||||
\item Import the new backup:
|
||||
\begin{verbatim}
|
||||
ejabberdctl install_fallback $NEWFILE
|
||||
\end{verbatim}
|
||||
|
||||
\item Stop ejabberd:
|
||||
\begin{verbatim}
|
||||
ejabberdctl stop
|
||||
\end{verbatim}
|
||||
You may see an error message in the log files, it's normal, so don't worry:
|
||||
\begin{verbatim}
|
||||
Mnesia(ejabberd@newmachine):
|
||||
** ERROR ** (ignoring core)
|
||||
** FATAL ** A fallback is installed and Mnesia must be restarted.
|
||||
Forcing shutdown after mnesia_down from ejabberd@newmachine...
|
||||
\end{verbatim}
|
||||
|
||||
\item Now you can finally start ejabberd:
|
||||
\begin{verbatim}
|
||||
ejabberdctl start
|
||||
ejabberdctl restore $NEWFILE
|
||||
\end{verbatim}
|
||||
|
||||
\item Check that the information of the old database is available: accounts, rosters...
|
||||
@@ -5060,7 +4915,7 @@ following steps:
|
||||
\item Copy \verb|~ejabberd/.erlang.cookie| file from \term{first} to
|
||||
\term{second}.
|
||||
|
||||
(alt) You can also add `\verb|-setcookie content_of_.erlang.cookie|'
|
||||
(alt) You can also add `\verb|-cookie content_of_.erlang.cookie|'
|
||||
option to all `\shell{erl}' commands below.
|
||||
|
||||
\item On \term{second} run the following command as the \ejabberd{} daemon user,
|
||||
@@ -5068,7 +4923,7 @@ following steps:
|
||||
|
||||
\begin{verbatim}
|
||||
erl -sname ejabberd \
|
||||
-mnesia dir '"/var/lib/ejabberd/"' \
|
||||
-mnesia dir "/var/lib/ejabberd/" \
|
||||
-mnesia extra_db_nodes "['ejabberd@first']" \
|
||||
-s mnesia
|
||||
\end{verbatim}
|
||||
@@ -5337,7 +5192,7 @@ Thanks to all people who contributed to this guide:
|
||||
\makechapter{copyright}{Copyright Information}
|
||||
|
||||
Ejabberd Installation and Operation Guide.\\
|
||||
Copyright \copyright{} 2003 --- 2010 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
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
|
||||
Release Notes
|
||||
ejabberd 2.1.1
|
||||
|
||||
ejabberd 2.1.1 is the first bugfix release in ejabberd 2.1.x branch.
|
||||
|
||||
ejabberd 2.1.1 includes several important bugfixes.
|
||||
More details of those fixes can be retrieved from:
|
||||
http://redir.process-one.net/ejabberd-2.1.1
|
||||
|
||||
The new code can be downloaded from ejabberd download page:
|
||||
http://www.process-one.net/en/ejabberd/
|
||||
|
||||
|
||||
The changes are:
|
||||
|
||||
* Core
|
||||
- Call ejabberd_router:route/3 instead of sending a message
|
||||
- Can't connect if starttls_required and zlib are set
|
||||
- Routes vCard request to the occupant full JID, but should to bare JID
|
||||
- S2S: fix allow_host/2 on subdomains. added hook s2s_allow_host
|
||||
|
||||
* MUC
|
||||
- Support converting one-to-one chat to MUC
|
||||
- Add support for serving a Unique Room Name
|
||||
|
||||
* Publish Subscribe
|
||||
- Receive same last published PEP items at reconnect if several resources online
|
||||
- Typo in mod_pubsub_odbc breaks Service Discovery and more
|
||||
|
||||
* Web
|
||||
- Fix memory and port leak when TLS is enabled in HTTP
|
||||
- WebAdmin doesn't report correct last activity with postgresql backend
|
||||
- Option to define custom HTTP headers in mod_http_fileserver
|
||||
- Show informative webpage when browsing the HTTP-Poll page
|
||||
|
||||
* Other
|
||||
- Change captcha.sh to not depend on bash
|
||||
- Generate main XML file also when exporting only a vhost
|
||||
- Fix last newline in ejabberdctl result
|
||||
- Guide: fix -setcookie, mod_pubsub_odbc host, content_types
|
||||
|
||||
|
||||
Bug reports
|
||||
|
||||
You can officially report bugs on ProcessOne support site:
|
||||
http://support.process-one.net/
|
||||
@@ -1,51 +0,0 @@
|
||||
|
||||
Release Notes
|
||||
ejabberd 2.1.2
|
||||
|
||||
ejabberd 2.1.2 is the second bugfix release in ejabberd 2.1.x branch.
|
||||
|
||||
ejabberd 2.1.2 includes several bugfixes.
|
||||
More details of those fixes can be retrieved from:
|
||||
http://redir.process-one.net/ejabberd-2.1.2
|
||||
|
||||
The new code can be downloaded from ejabberd download page:
|
||||
http://www.process-one.net/en/ejabberd/
|
||||
|
||||
|
||||
The major changes are:
|
||||
|
||||
* Core
|
||||
- Close sessions that were half connected
|
||||
- Fix SASL PLAIN authentication message for RFC4616 compliance
|
||||
- Fix support for old Erlang/OTP R10 and R11
|
||||
- Return proper error (not 'conflict') when register is forbidden by ACL
|
||||
- When ejabberd stops, send stream close to clients
|
||||
|
||||
* ejabberdctl
|
||||
- Check for EGID in ejabberdctl command
|
||||
- Command to stop ejabberd informing users, with grace period
|
||||
- If there's a problem in config file, display config lines and stop node
|
||||
|
||||
* MUC
|
||||
- Kick occupants with reason when room is stopped due to MUC shutdown
|
||||
- Write in room log when a room is created, destroyed, started, stopped
|
||||
|
||||
* PubSub and PEP
|
||||
- Don't call gen_server on internal event (improves performance and scalability)
|
||||
- Fix duplicate SHIM header in Pubsub message
|
||||
- Notification messages of Pubsub node config change contained a SHIM header
|
||||
- SubID SHIM header missing in Pubsub message with multiple
|
||||
subscriptions on the same node
|
||||
- PEP: last published item not sent from unavailable users when the
|
||||
subscription is implicit (XEP-0115)
|
||||
- pep_mapping not working due to Node type mismatch
|
||||
|
||||
* WebAdmin
|
||||
- If big offline message queue, show only subset on WebAdmin
|
||||
- Support in user list page of WebAdmin when mod_offline is disabled
|
||||
|
||||
|
||||
Bug reports
|
||||
|
||||
You can officially report bugs on ProcessOne support site:
|
||||
http://support.process-one.net/
|
||||
@@ -1,91 +0,0 @@
|
||||
|
||||
Release Notes
|
||||
ejabberd 2.1.3
|
||||
|
||||
ejabberd 2.1.3 is the third release in ejabberd 2.1.x branch.
|
||||
|
||||
ejabberd 2.1.3 includes many bugfixes, and some improvements.
|
||||
More details of those fixes can be retrieved from:
|
||||
http://redir.process-one.net/ejabberd-2.1.3
|
||||
|
||||
The new code can be downloaded from ejabberd download page:
|
||||
http://www.process-one.net/en/ejabberd/
|
||||
|
||||
|
||||
This is the full list of changes:
|
||||
|
||||
* Client connections
|
||||
- Avoid 'invalid' value in iq record
|
||||
- Avoid resending stream:error stanzas on terminate (EJAB-1180)
|
||||
- Close also legacy sessions that were half connected (EJAB-1165)
|
||||
- iq_query_info/1 now returns 'invalid' if XMLNS is invalid
|
||||
- New ejabberd_c2s option support: max_fsm_queue
|
||||
- Rewrite mnesia counter functions to use dirty_update_counter (EJAB-1177)
|
||||
- Run user_receive_packet also when sending offline messages (EJAB-1193)
|
||||
- Use p1_fsm behaviour in c2s FSM (EJAB-1173)
|
||||
|
||||
* Clustering
|
||||
- Fix cluster race condition in route read
|
||||
- New command to set master Mnesia node
|
||||
- Use mnesia:async_dirty when cleaning table from failed node
|
||||
|
||||
* Documentation
|
||||
- Add quotes in documentation of some erl arguments (EJAB-1191)
|
||||
- Add option access_from (EJAB-1187)
|
||||
- Add option max_fsm_queue (EJAB-1185)
|
||||
- Fix documentation installation, no need for executable permission (EJAB-1170)
|
||||
- Fix typo in EJABBERD_BIN_PATH (EJAB-891)
|
||||
- Fix typos in example config comments (EJAB-1192)
|
||||
|
||||
* ejabberdctl
|
||||
- Support concurrent connections with bound connection names
|
||||
- Add support for Jot in ctl and TTY in debug
|
||||
- Support help command names with old - characters
|
||||
- Fix to really use the variable ERL_PROCESSES
|
||||
|
||||
* Erlang compatibility
|
||||
- Don't call queue:filter/2 to keep compatibility with older Erlang versions
|
||||
- Use alternative of file:read_line/1 to not require R13B02
|
||||
|
||||
* HTTP
|
||||
- Add new debugging hook to the http receiving process
|
||||
- Allow a request_handler to serve a file in root of HTTP
|
||||
|
||||
* HTTP-Bind (BOSH)
|
||||
- Cross-domain HTTP-Bind support (EJAB-1168)
|
||||
- Hibernate http-bind process after handling a request
|
||||
- Reduce verbosity of HTTP Binding log messages
|
||||
|
||||
* LDAP
|
||||
- Document ldap_dn_filter, fetch only needed attributes in search (EJAB-1204)
|
||||
- Use "%u" pattern as default for ldap_uids (EJAB-1203)
|
||||
|
||||
* Localization
|
||||
- Fix German translation (EJAB-1195)
|
||||
- Fix Russian translation
|
||||
|
||||
* ODBC
|
||||
- Fix MSSQL support, which was broken (EJAB-1201)
|
||||
- Improved SQL reconnect behaviour
|
||||
|
||||
* Pubsub, PEP and Caps
|
||||
- Add extended stanza addressing 'replyto' on PEP (EJAB-1198)
|
||||
- Add pubsub#purge_offline (EJAB-1186)
|
||||
- Fix pubsub#title option (EJAB-1190)
|
||||
- Fix remove_user for node subscriptions (EJAB-1172)
|
||||
- Optimizations in mod_caps
|
||||
|
||||
* Other
|
||||
- mod_register: Add new acl access_from, default is to deny
|
||||
- mod_sic: new module for the experimental XEP-0279 Server IP Check (EJAB-1205)
|
||||
- PIEFXIS: Catch errors when exporting to PIEFXIS file (EJAB-1178)
|
||||
- Proxy65: new option "hostname" (EJAB-838)
|
||||
- Roster: Fix resending authorization problem
|
||||
- Shared Roster Groups: get contacts nickname from vcard (EJAB-114)
|
||||
- S2S: Improved s2s connections clean up (EJAB-1202)
|
||||
|
||||
|
||||
Bug reports
|
||||
|
||||
You can officially report bugs on ProcessOne support site:
|
||||
http://support.process-one.net/
|
||||
@@ -1,80 +0,0 @@
|
||||
|
||||
Release Notes
|
||||
ejabberd 2.1.4
|
||||
|
||||
ejabberd 2.1.4 is the fourth release in ejabberd 2.1.x branch,
|
||||
and includes many small bugfixes and improvements.
|
||||
|
||||
Read more details about the changes in:
|
||||
http://redir.process-one.net/ejabberd-2.1.4
|
||||
|
||||
Download the source code and installers from:
|
||||
http://www.process-one.net/en/ejabberd/
|
||||
|
||||
|
||||
This is the full list of changes:
|
||||
|
||||
* Authentication
|
||||
- Extauth: Optionally cache extauth users in mnesia (EJAB-641)
|
||||
- LDAP: Allow inband password change (EJAB-199)
|
||||
- LDAP: Extensible match support (EJAB-722)
|
||||
- LDAP: New option ldap_tls_verify is added (EJAB-1229)
|
||||
- PAM: New option pam_userinfotype to provide username or JID (EJAB-652)
|
||||
|
||||
* HTTP
|
||||
- Add xml default content type
|
||||
- Don't show HTTP request in logs, because reveals password (EJAB-1231)
|
||||
- Move HTTP session timeout log from warning level to info
|
||||
- New Access rule webadmin_view for read-only
|
||||
|
||||
* HTTP-Bind (BOSH)
|
||||
- Change max inactivity from 30 to 120 seconds
|
||||
- Export functions to facilitate prebinding methods
|
||||
- Use dirty_delete when removing the session
|
||||
- Remove an unneeded delay of 100 milliseconds
|
||||
|
||||
* Pubsub, PEP and Caps
|
||||
- Enforce pubsub#presence_based_delivery (EJAB-1221)
|
||||
- Enforce pubsub#show_values subscription option (EJAB-1096)
|
||||
- Fix error code when unsubscribing from a non-existent node
|
||||
- Fix to send node notifications (EJAB-1225)
|
||||
- Full support for XEP-0115 v1.5 (EJAB-1223)(EJAB-1189)
|
||||
- Make last_item_cache feature to be cluster aware
|
||||
- Prevent orphaned pubsub node (EJAB-1233)
|
||||
- Send created node notifications
|
||||
|
||||
* Other
|
||||
- Bounce messages when closing c2s session
|
||||
- Bugfixes when handling Service Discovery to contacts (EJAB-1207)
|
||||
- Compilation of ejabberd_debug.erl is now optional
|
||||
- Don't send error stanza as reply to error stanza (EJAB-930)
|
||||
- Don't store blocked messages in offline queue
|
||||
- Reduce verbosity of log when captcha_cmd is checked but not configured
|
||||
- Use a standard method to get a random seed (EJAB-1229)
|
||||
- Commands: new update_list and update to update modified modules (EJAB-1237)
|
||||
- Localization: Updated most translations
|
||||
- MUC: Refactor code to reduce calls to get_affiliation and get_role
|
||||
- ODBC: Add created_at column also to PostgreSQL schema
|
||||
- Vcard: Automatic vcard avatar addition in presence
|
||||
|
||||
|
||||
Upgrading From previous ejabberd releases:
|
||||
|
||||
- If you use PostgreSQL, maybe you want to add the column created_at
|
||||
to several tables. This is only a suggestion; ejabberd doesn't use
|
||||
that column. Add it to your existing database executing those SQL
|
||||
statements:
|
||||
|
||||
ALTER TABLE users ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT now();
|
||||
ALTER TABLE rosterusers ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT now();
|
||||
ALTER TABLE spool ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT now();
|
||||
ALTER TABLE vcard ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT now();
|
||||
ALTER TABLE privacy_list ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT now();
|
||||
ALTER TABLE privacy_storage ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT now();
|
||||
|
||||
|
||||
Bug reports
|
||||
|
||||
You can officially report bugs on ProcessOne support site:
|
||||
http://support.process-one.net/
|
||||
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
% ejabberd version (automatically generated).
|
||||
\newcommand{\version}{2.1.4}
|
||||
\newcommand{\version}{2.1.0}
|
||||
|
||||
Executable → Regular
+14
-17
@@ -34,13 +34,11 @@ EFLAGS += @ERLANG_SSL39@ -pa .
|
||||
|
||||
# make debug=true to compile Erlang module with debug informations.
|
||||
ifdef debug
|
||||
EFLAGS+=+debug_info +export_all
|
||||
EFLAGS+=+debug_info
|
||||
endif
|
||||
|
||||
DEBUGTOOLS = ejabberd_debug.erl
|
||||
ifdef ejabberd_debug
|
||||
EFLAGS+=-Dejabberd_debug
|
||||
SOURCES+=$(DEBUGTOOLS)
|
||||
endif
|
||||
|
||||
ifeq (@hipe@, true)
|
||||
@@ -71,8 +69,7 @@ SUBDIRS = @mod_irc@ @mod_pubsub@ @mod_muc@ @mod_proxy65@ @eldap@ @pam@ @web@ str
|
||||
ERLSHLIBS = expat_erl.so
|
||||
ERLBEHAVS = cyrsasl.erl gen_mod.erl p1_fsm.erl
|
||||
SOURCES_ALL = $(wildcard *.erl)
|
||||
SOURCES_MISC = $(ERLBEHAVS) $(DEBUGTOOLS)
|
||||
SOURCES += $(filter-out $(SOURCES_MISC),$(SOURCES_ALL))
|
||||
SOURCES = $(filter-out $(ERLBEHAVS),$(SOURCES_ALL))
|
||||
ERLBEHAVBEAMS = $(ERLBEHAVS:.erl=.beam)
|
||||
BEAMS = $(SOURCES:.erl=.beam)
|
||||
|
||||
@@ -113,9 +110,6 @@ MSGSDIR = $(PRIVDIR)/msgs
|
||||
# /var/lib/ejabberd/
|
||||
SPOOLDIR = $(DESTDIR)@localstatedir@/lib/ejabberd
|
||||
|
||||
# /var/lock/ejabberdctl
|
||||
CTLLOCKDIR = $(DESTDIR)@localstatedir@/lock/ejabberdctl
|
||||
|
||||
# /var/lib/ejabberd/.erlang.cookie
|
||||
COOKIEFILE = $(SPOOLDIR)/.erlang.cookie
|
||||
|
||||
@@ -238,11 +232,6 @@ install: all
|
||||
chmod -R 750 $(SPOOLDIR)
|
||||
[ ! -f $(COOKIEFILE) ] || { $(CHOWN_COMMAND) @INSTALLUSER@ $(COOKIEFILE) >$(CHOWN_OUTPUT) ; chmod 400 $(COOKIEFILE) ; }
|
||||
#
|
||||
# ejabberdctl lock directory
|
||||
install -d -m 750 $(O_USER) $(CTLLOCKDIR)
|
||||
$(CHOWN_COMMAND) -R @INSTALLUSER@ $(CTLLOCKDIR) >$(CHOWN_OUTPUT)
|
||||
chmod -R 750 $(CTLLOCKDIR)
|
||||
#
|
||||
# Log directory
|
||||
install -d -m 750 $(O_USER) $(LOGDIR)
|
||||
$(CHOWN_COMMAND) -R @INSTALLUSER@ $(LOGDIR) >$(CHOWN_OUTPUT)
|
||||
@@ -250,9 +239,9 @@ install: all
|
||||
#
|
||||
# Documentation
|
||||
install -d $(DOCDIR)
|
||||
install -m 644 ../doc/guide.html $(DOCDIR)
|
||||
install -m 644 ../doc/*.png $(DOCDIR)
|
||||
install -m 644 ../doc/*.txt $(DOCDIR)
|
||||
install ../doc/guide.html $(DOCDIR)
|
||||
install ../doc/*.png $(DOCDIR)
|
||||
install ../doc/*.txt $(DOCDIR)
|
||||
|
||||
uninstall: uninstall-binary
|
||||
|
||||
@@ -276,7 +265,6 @@ uninstall-all: uninstall-binary
|
||||
rm -rf $(ETCDIR)
|
||||
rm -rf $(EJABBERDDIR)
|
||||
rm -rf $(SPOOLDIR)
|
||||
rm -rf $(CTLLOCKDIR)
|
||||
rm -rf $(LOGDIR)
|
||||
|
||||
clean: clean-recursive clean-local
|
||||
@@ -298,3 +286,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
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
%%% Created : 18 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
+6
-7
@@ -1,11 +1,11 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% File : adhoc.erl
|
||||
%%% Author : Magnus Henoch <henoch@dtek.chalmers.se>
|
||||
%%% Purpose : Provide helper functions for ad-hoc commands (XEP-0050)
|
||||
%%% Purpose : Provide helper functions for ad-hoc commands (JEP-0050)
|
||||
%%% Created : 31 Oct 2005 by Magnus Henoch <henoch@dtek.chalmers.se>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -44,11 +44,10 @@ parse_request(#iq{type = set, lang = Lang, sub_el = SubEl, xmlns = ?NS_COMMANDS}
|
||||
Action = xml:get_tag_attr_s("action", SubEl),
|
||||
XData = find_xdata_el(SubEl),
|
||||
{xmlelement, _, _, AllEls} = SubEl,
|
||||
Others = case XData of
|
||||
false ->
|
||||
AllEls;
|
||||
_ ->
|
||||
lists:delete(XData, AllEls)
|
||||
if XData ->
|
||||
Others = lists:delete(XData, AllEls);
|
||||
true ->
|
||||
Others = AllEls
|
||||
end,
|
||||
|
||||
#adhoc_request{lang = Lang,
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
+7
-5
@@ -1,11 +1,11 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% File : configure.erl
|
||||
%%% Author : Alexey Shchepin <alexey@process-one.net>
|
||||
%%% Purpose :
|
||||
%%% Purpose :
|
||||
%%% Created : 27 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -58,7 +58,7 @@ start() ->
|
||||
end,
|
||||
|
||||
EVersion = "ERLANG_VERSION = " ++ erlang:system_info(version) ++ "\n",
|
||||
EIDirS = "EI_DIR = " ++ code:lib_dir(erl_interface) ++ "\n",
|
||||
EIDirS = "EI_DIR = " ++ code:lib_dir("erl_interface") ++ "\n",
|
||||
RootDirS = "ERLANG_DIR = " ++ code:root_dir() ++ "\n",
|
||||
%% Load the ejabberd application description so that ?VERSION can read the vsn key
|
||||
application:load(ejabberd),
|
||||
@@ -67,8 +67,8 @@ start() ->
|
||||
OpenSSLDir = "OPENSSL_DIR = c:\\sdk\\OpenSSL\n",
|
||||
DBType = "DBTYPE = generic\n", %% 'generic' or 'mssql'
|
||||
|
||||
SSLDir = "SSLDIR = " ++ code:lib_dir(ssl) ++ "\n",
|
||||
StdLibDir = "STDLIBDIR = " ++ code:lib_dir(stdlib) ++ "\n",
|
||||
SSLDir = "SSLDIR = " ++ code:lib_dir("ssl") ++ "\n",
|
||||
StdLibDir = "STDLIBDIR = " ++ code:lib_dir("stdlib") ++ "\n",
|
||||
|
||||
file:write_file("Makefile.inc",
|
||||
list_to_binary(EVersion ++
|
||||
@@ -87,3 +87,5 @@ start() ->
|
||||
ZlibDir ++
|
||||
ZlibLib)),
|
||||
halt().
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
%%% Created : 8 Mar 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
%%% Created : 23 Aug 2005 by Magnus Henoch <henoch@dtek.chalmers.se>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%%% Created : 11 Mar 2003 by Alexey Shchepin <alexey@sevcom.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
+3
-28
@@ -5,7 +5,7 @@
|
||||
%%% Created : 8 Mar 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -44,7 +44,7 @@ mech_new(_Host, _GetPassword, CheckPassword, _CheckPasswordDigest) ->
|
||||
{ok, #state{check_password = CheckPassword}}.
|
||||
|
||||
mech_step(State, ClientIn) ->
|
||||
case prepare(ClientIn) of
|
||||
case parse(ClientIn) of
|
||||
[AuthzId, User, Password] ->
|
||||
case (State#state.check_password)(User, Password) of
|
||||
{true, AuthModule} ->
|
||||
@@ -57,24 +57,6 @@ mech_step(State, ClientIn) ->
|
||||
{error, "bad-protocol"}
|
||||
end.
|
||||
|
||||
prepare(ClientIn) ->
|
||||
case parse(ClientIn) of
|
||||
[[], UserMaybeDomain, Password] ->
|
||||
case parse_domain(UserMaybeDomain) of
|
||||
%% <NUL>login@domain<NUL>pwd
|
||||
[User, _Domain] ->
|
||||
[UserMaybeDomain, User, Password];
|
||||
%% <NUL>login<NUL>pwd
|
||||
[User] ->
|
||||
["", User, Password]
|
||||
end;
|
||||
%% login@domain<NUL>login<NUL>pwd
|
||||
[AuthzId, User, Password] ->
|
||||
[AuthzId, User, Password];
|
||||
_ ->
|
||||
error
|
||||
end.
|
||||
|
||||
|
||||
parse(S) ->
|
||||
parse1(S, "", []).
|
||||
@@ -89,12 +71,5 @@ parse1([], S, T) ->
|
||||
lists:reverse([lists:reverse(S) | T]).
|
||||
|
||||
|
||||
parse_domain(S) ->
|
||||
parse_domain1(S, "", []).
|
||||
|
||||
parse_domain1([$@ | Cs], S, T) ->
|
||||
parse_domain1(Cs, "", [lists:reverse(S) | T]);
|
||||
parse_domain1([C | Cs], S, T) ->
|
||||
parse_domain1(Cs, [C | S], T);
|
||||
parse_domain1([], S, T) ->
|
||||
lists:reverse([lists:reverse(S) | T]).
|
||||
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
{application, ejabberd,
|
||||
[{description, "ejabberd"},
|
||||
{vsn, "2.1.4"},
|
||||
{vsn, "2.1.0"},
|
||||
{modules, [acl,
|
||||
adhoc,
|
||||
configure,
|
||||
|
||||
+34
-41
@@ -5,7 +5,7 @@
|
||||
|
||||
%%% 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 with
|
||||
%%% 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/
|
||||
|
||||
@@ -26,11 +26,11 @@
|
||||
%%% [http_poll, web_admin, tls]
|
||||
%%%
|
||||
%%% - A keyword of ejabberd is a word in lowercase.
|
||||
%%% Strings are enclosed in "" and can contain spaces, dots, ...
|
||||
%%% The strings are enclosed in "" and can have spaces, dots...
|
||||
%%% {language, "en"}.
|
||||
%%% {ldap_rootdn, "dc=example,dc=com"}.
|
||||
%%%
|
||||
%%% - This term includes a tuple, a keyword, a list, and two strings:
|
||||
%%% - This term includes a tuple, a keyword, a list and two strings:
|
||||
%%% {hosts, ["jabber.example.net", "im.example.com"]}.
|
||||
%%%
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
|
||||
%%
|
||||
%% watchdog_admins: Only useful for developers: if an ejabberd process
|
||||
%% consumes a lot of memory, send live notifications to these XMPP
|
||||
%% 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 XMPP servers.
|
||||
%% route_subdomains: Delegate subdomains to other XMPP server.
|
||||
%% For example, if this ejabberd serves example.org and you want
|
||||
%% to allow communication with an XMPP server called im.example.org.
|
||||
%% to allow communication with a XMPP server called im.example.org.
|
||||
%%
|
||||
%%{route_subdomains, s2s}.
|
||||
|
||||
@@ -102,8 +102,8 @@
|
||||
%%%' LISTENING PORTS
|
||||
|
||||
%%
|
||||
%% listen: The ports ejabberd will listen on, which service each is handled
|
||||
%% by and what options to start it with.
|
||||
%% listen: Which ports will ejabberd listen, which service handles it
|
||||
%% and what options to start it with.
|
||||
%%
|
||||
{listen,
|
||||
[
|
||||
@@ -111,8 +111,8 @@
|
||||
{5222, ejabberd_c2s, [
|
||||
|
||||
%%
|
||||
%% If TLS is compiled in and you installed a SSL
|
||||
%% certificate, specify the full path to the
|
||||
%% If TLS is compiled and you installed a SSL
|
||||
%% certificate, put the correct path to the
|
||||
%% file and uncomment this line:
|
||||
%%
|
||||
%%{certfile, "/path/to/ssl.pem"}, starttls,
|
||||
@@ -123,7 +123,7 @@
|
||||
]},
|
||||
|
||||
%%
|
||||
%% To enable the old SSL connection method on port 5223:
|
||||
%% To enable the old SSL connection method in port 5223:
|
||||
%%
|
||||
%%{5223, ejabberd_c2s, [
|
||||
%% {access, c2s},
|
||||
@@ -138,7 +138,7 @@
|
||||
]},
|
||||
|
||||
%%
|
||||
%% ejabberd_service: Interact with external components (transports, ...)
|
||||
%% ejabberd_service: Interact with external components (transports...)
|
||||
%%
|
||||
%%{8888, ejabberd_service, [
|
||||
%% {access, all},
|
||||
@@ -249,14 +249,14 @@
|
||||
%%{ldap_encrypt, none}.
|
||||
%%{ldap_encrypt, tls}.
|
||||
%%
|
||||
%% Port to connect to on LDAP servers:
|
||||
%% Port connect to LDAP servers:
|
||||
%%{ldap_port, 389}.
|
||||
%%{ldap_port, 636}.
|
||||
%%
|
||||
%% LDAP manager:
|
||||
%%{ldap_rootdn, "dc=example,dc=com"}.
|
||||
%%
|
||||
%% Password of LDAP manager:
|
||||
%% Password to LDAP manager:
|
||||
%%{ldap_password, "******"}.
|
||||
%%
|
||||
%% Search base of LDAP directory:
|
||||
@@ -286,11 +286,11 @@
|
||||
%%%. ==============
|
||||
%%%' DATABASE SETUP
|
||||
|
||||
%% ejabberd by default uses the internal Mnesia database,
|
||||
%% so you do not necessarily need this section.
|
||||
%% ejabberd uses by default the internal Mnesia database,
|
||||
%% so you can avoid this section.
|
||||
%% This section provides configuration examples in case
|
||||
%% you want to use other database backends.
|
||||
%% Please consult the ejabberd Guide for details on database creation.
|
||||
%% Please consult the ejabberd Guide for details about database creation.
|
||||
|
||||
%%
|
||||
%% MySQL server:
|
||||
@@ -324,8 +324,8 @@
|
||||
%%{odbc_pool_size, 10}.
|
||||
|
||||
%%
|
||||
%% Interval to make a dummy SQL request to keep the connections to the
|
||||
%% database alive. Specify in seconds: for example 28800 means 8 hours
|
||||
%% Interval to make a dummy SQL request to keep alive the connections
|
||||
%% to the database. Specify in seconds: for example 28800 means 8 hours
|
||||
%%
|
||||
%%{odbc_keepalive_interval, undefined}.
|
||||
|
||||
@@ -334,28 +334,22 @@
|
||||
%%%' TRAFFIC SHAPERS
|
||||
|
||||
%%
|
||||
%% The "normal" shaper limits traffic speed to 1000 B/s
|
||||
%% The "normal" shaper limits traffic speed to 1.000 B/s
|
||||
%%
|
||||
{shaper, normal, {maxrate, 1000}}.
|
||||
|
||||
%%
|
||||
%% The "fast" shaper limits traffic speed to 50000 B/s
|
||||
%% The "fast" shaper limits traffic speed to 50.000 B/s
|
||||
%%
|
||||
{shaper, fast, {maxrate, 50000}}.
|
||||
|
||||
%%
|
||||
%% This option specifies the maximum number of elements in the queue
|
||||
%% of the FSM. Refer to the documentation for details.
|
||||
%%
|
||||
{max_fsm_queue, 1000}.
|
||||
|
||||
|
||||
%%%. ====================
|
||||
%%%' ACCESS CONTROL LISTS
|
||||
|
||||
%%
|
||||
%% The 'admin' ACL grants administrative privileges to XMPP accounts.
|
||||
%% You can put here as many accounts as you want.
|
||||
%% You can put as many accounts as you want.
|
||||
%%
|
||||
%%{acl, admin, {user, "aleksey", "localhost"}}.
|
||||
%%{acl, admin, {user, "ermine", "example.org"}}.
|
||||
@@ -396,7 +390,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}]}.
|
||||
@@ -405,41 +399,41 @@
|
||||
{access, c2s, [{deny, blocked},
|
||||
{allow, all}]}.
|
||||
|
||||
%% For C2S connections, all users except admins use the "normal" shaper
|
||||
%% For C2S connections, all users except admins use "normal" shaper
|
||||
{access, c2s_shaper, [{none, admin},
|
||||
{normal, all}]}.
|
||||
|
||||
%% All S2S connections use the "fast" shaper
|
||||
%% All S2S connections use "fast" shaper
|
||||
{access, s2s_shaper, [{fast, all}]}.
|
||||
|
||||
%% Only admins can send announcement messages:
|
||||
{access, announce, [{allow, admin}]}.
|
||||
|
||||
%% Only admins can use the configuration interface:
|
||||
%% Only admins can use configuration interface:
|
||||
{access, configure, [{allow, admin}]}.
|
||||
|
||||
%% Admins of this server are also admins of the MUC service:
|
||||
%% 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 the MUC service:
|
||||
%% All users are allowed to use MUC service:
|
||||
{access, muc, [{allow, all}]}.
|
||||
|
||||
%% Only accounts on the local ejabberd server can create Pubsub nodes:
|
||||
%% 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'.
|
||||
{access, register, [{allow, all}]}.
|
||||
|
||||
%% By default the frequency of account registrations from the same IP
|
||||
%% is limited to 1 account every 10 minutes. To disable, specify: infinity
|
||||
%% 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}.
|
||||
|
||||
%%
|
||||
%% Define specific Access Rules in a virtual host.
|
||||
%% Define specific Access rules in a virtual host.
|
||||
%%
|
||||
%%{host_config, "localhost",
|
||||
%% [
|
||||
@@ -496,7 +490,7 @@
|
||||
{mod_irc, []},
|
||||
{mod_http_bind, []},
|
||||
%%{mod_http_fileserver, [
|
||||
%% {docroot, "/var/www"},
|
||||
%% {docroot, "/var/www"},
|
||||
%% {accesslog, "/var/log/ejabberd/access.log"}
|
||||
%% ]},
|
||||
{mod_last, []},
|
||||
@@ -515,8 +509,7 @@
|
||||
%%{mod_proxy65,[]},
|
||||
{mod_pubsub, [
|
||||
{access_createnode, pubsub_createnode},
|
||||
{ignore_pep_from_offline, true}, % reduces resource comsumption, but XEP incompliant
|
||||
%%{ignore_pep_from_offline, false}, % XEP compliant, but increases resource comsumption
|
||||
{ignore_pep_from_offline, true},
|
||||
{last_item_cache, false},
|
||||
{plugins, ["flat", "hometree", "pep"]} % pep requires mod_caps
|
||||
]},
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
%%% Created : 16 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
+3
-109
@@ -5,7 +5,7 @@
|
||||
%%% Created : 7 May 2006 by Mickael Remond <mremond@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -30,9 +30,6 @@
|
||||
-export([start/0, stop/0,
|
||||
%% Server
|
||||
status/0, reopen_log/0,
|
||||
stop_kindly/2, send_service_message_all_mucs/2,
|
||||
%% Erlang
|
||||
update_list/0, update/1,
|
||||
%% Accounts
|
||||
register/3, unregister/2,
|
||||
registered_users/1,
|
||||
@@ -41,7 +38,6 @@
|
||||
%% Purge DB
|
||||
delete_expired_messages/0, delete_old_messages/1,
|
||||
%% Mnesia
|
||||
set_master/1,
|
||||
backup_mnesia/1, restore_mnesia/1,
|
||||
dump_mnesia/1, dump_table/2, load_mnesia/1,
|
||||
install_fallback_mnesia/1,
|
||||
@@ -83,11 +79,6 @@ commands() ->
|
||||
desc = "Reopen the log files",
|
||||
module = ?MODULE, function = reopen_log,
|
||||
args = [], result = {res, rescode}},
|
||||
#ejabberd_commands{name = stop_kindly, tags = [server],
|
||||
desc = "Inform users and rooms, wait, and stop the server",
|
||||
module = ?MODULE, function = stop_kindly,
|
||||
args = [{delay, integer}, {announcement, string}],
|
||||
result = {res, rescode}},
|
||||
#ejabberd_commands{name = get_loglevel, tags = [logs, server],
|
||||
desc = "Get the current loglevel",
|
||||
module = ejabberd_loglevel, function = get,
|
||||
@@ -97,17 +88,6 @@ commands() ->
|
||||
{leveldesc, string}
|
||||
]}}},
|
||||
|
||||
#ejabberd_commands{name = update_list, tags = [server],
|
||||
desc = "List modified modules that can be updated",
|
||||
module = ?MODULE, function = update_list_modified,
|
||||
args = [],
|
||||
result = {modules, {list, {module, string}}}},
|
||||
#ejabberd_commands{name = update, tags = [server],
|
||||
desc = "Update the given module, or use the keyword: all",
|
||||
module = ?MODULE, function = update,
|
||||
args = [{module, string}],
|
||||
result = {res, rescode}},
|
||||
|
||||
#ejabberd_commands{name = register, tags = [accounts],
|
||||
desc = "Register a user",
|
||||
module = ?MODULE, function = register,
|
||||
@@ -157,16 +137,10 @@ commands() ->
|
||||
args = [{days, integer}], result = {res, rescode}},
|
||||
|
||||
#ejabberd_commands{name = rename_default_nodeplugin, tags = [mnesia],
|
||||
desc = "Update PubSub table from old ejabberd trunk SVN to 2.1.0",
|
||||
desc = "Update PubSub table from ejabberd trunk SVN to 2.1.0",
|
||||
module = mod_pubsub, function = rename_default_nodeplugin,
|
||||
args = [], result = {res, rescode}},
|
||||
|
||||
#ejabberd_commands{name = set_master, tags = [mnesia],
|
||||
desc = "Set master node of the clustered Mnesia tables",
|
||||
longdesc = "If you provide as nodename \"self\", this "
|
||||
"node will be set as its own master.",
|
||||
module = ?MODULE, function = set_master,
|
||||
args = [{nodename, string}], result = {res, restuple}},
|
||||
#ejabberd_commands{name = mnesia_change_nodename, tags = [mnesia],
|
||||
desc = "Change the erlang node name in a backup file",
|
||||
module = ?MODULE, function = mnesia_change_nodename,
|
||||
@@ -241,72 +215,6 @@ get_sasl_error_logger_type () ->
|
||||
_ -> all
|
||||
end.
|
||||
|
||||
%%%
|
||||
%%% Stop Kindly
|
||||
%%%
|
||||
|
||||
stop_kindly(DelaySeconds, AnnouncementText) ->
|
||||
Subject = io_lib:format("Server stop in ~p seconds!", [DelaySeconds]),
|
||||
WaitingDesc = io_lib:format("Waiting ~p seconds", [DelaySeconds]),
|
||||
Steps = [
|
||||
{"Stopping ejabberd port listeners",
|
||||
ejabberd_listener, stop_listeners, []},
|
||||
{"Sending announcement to connected users",
|
||||
mod_announce, send_announcement_to_all,
|
||||
[?MYNAME, Subject, AnnouncementText]},
|
||||
{"Sending service message to MUC rooms",
|
||||
ejabberd_admin, send_service_message_all_mucs,
|
||||
[Subject, AnnouncementText]},
|
||||
{WaitingDesc, timer, sleep, [DelaySeconds * 1000]},
|
||||
{"Stopping ejabberd", application, stop, [ejabberd]},
|
||||
{"Stopping Mnesia", mnesia, stop, []},
|
||||
{"Stopping Erlang node", init, stop, []}
|
||||
],
|
||||
NumberLast = length(Steps),
|
||||
TimestampStart = calendar:datetime_to_gregorian_seconds({date(), time()}),
|
||||
lists:foldl(
|
||||
fun({Desc, Mod, Func, Args}, NumberThis) ->
|
||||
SecondsDiff =
|
||||
calendar:datetime_to_gregorian_seconds({date(), time()})
|
||||
- TimestampStart,
|
||||
io:format("[~p/~p ~ps] ~s... ",
|
||||
[NumberThis, NumberLast, SecondsDiff, Desc]),
|
||||
Result = apply(Mod, Func, Args),
|
||||
io:format("~p~n", [Result]),
|
||||
NumberThis+1
|
||||
end,
|
||||
1,
|
||||
Steps),
|
||||
ok.
|
||||
|
||||
send_service_message_all_mucs(Subject, AnnouncementText) ->
|
||||
Message = io_lib:format("~s~n~s", [Subject, AnnouncementText]),
|
||||
lists:foreach(
|
||||
fun(ServerHost) ->
|
||||
MUCHost = gen_mod:get_module_opt_host(
|
||||
ServerHost, mod_muc, "conference.@HOST@"),
|
||||
mod_muc:broadcast_service_message(MUCHost, Message)
|
||||
end,
|
||||
?MYHOSTS).
|
||||
|
||||
%%%
|
||||
%%% ejabberd_update
|
||||
%%%
|
||||
|
||||
update_list() ->
|
||||
{ok, _Dir, UpdatedBeams, _Script, _LowLevelScript, _Check} =
|
||||
ejabberd_update:update_info(),
|
||||
[atom_to_list(Beam) || Beam <- UpdatedBeams].
|
||||
|
||||
update("all") ->
|
||||
[update_module(ModStr) || ModStr <- update_list()];
|
||||
update(ModStr) ->
|
||||
update_module(ModStr).
|
||||
|
||||
update_module(ModuleNameString) ->
|
||||
ModuleName = list_to_atom(ModuleNameString),
|
||||
ejabberd_update:update([ModuleName]).
|
||||
|
||||
%%%
|
||||
%%% Account management
|
||||
%%%
|
||||
@@ -314,7 +222,7 @@ update_module(ModuleNameString) ->
|
||||
register(User, Host, Password) ->
|
||||
case ejabberd_auth:try_register(User, Host, Password) of
|
||||
{atomic, ok} ->
|
||||
{ok, io_lib:format("User ~s@~s successfully registered", [User, Host])};
|
||||
{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()]),
|
||||
@@ -377,20 +285,6 @@ delete_old_messages(Days) ->
|
||||
%%% Mnesia management
|
||||
%%%
|
||||
|
||||
set_master("self") ->
|
||||
set_master(node());
|
||||
set_master(NodeString) when is_list(NodeString) ->
|
||||
set_master(list_to_atom(NodeString));
|
||||
set_master(Node) when is_atom(Node) ->
|
||||
case mnesia:set_master_nodes([Node]) of
|
||||
ok ->
|
||||
{ok, ""};
|
||||
{error, Reason} ->
|
||||
String = io_lib:format("Can't set master node ~p at node ~p:~n~p",
|
||||
[Node, node(), Reason]),
|
||||
{error, String}
|
||||
end.
|
||||
|
||||
backup_mnesia(Path) ->
|
||||
case mnesia:backup(Path) of
|
||||
ok ->
|
||||
|
||||
+2
-11
@@ -5,7 +5,7 @@
|
||||
%%% Created : 31 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -77,15 +77,13 @@ start(_, _) ->
|
||||
prep_stop(State) ->
|
||||
stop_modules(),
|
||||
ejabberd_admin:stop(),
|
||||
broadcast_c2s_shutdown(),
|
||||
timer:sleep(5000),
|
||||
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(),
|
||||
ejabberd_debug:stop(),
|
||||
ok.
|
||||
|
||||
|
||||
@@ -200,13 +198,6 @@ add_windows_nameservers() ->
|
||||
lists:foreach(fun(IPT) -> inet_db:add_ns(IPT) end, IPTs).
|
||||
|
||||
|
||||
broadcast_c2s_shutdown() ->
|
||||
Children = supervisor:which_children(ejabberd_c2s_sup),
|
||||
lists:foreach(
|
||||
fun({_, C2SPid, _, _}) ->
|
||||
C2SPid ! system_shutdown
|
||||
end, Children).
|
||||
|
||||
%%%
|
||||
%%% PID file
|
||||
%%%
|
||||
|
||||
+2
-11
@@ -5,7 +5,7 @@
|
||||
%%% Created : 23 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -251,16 +251,7 @@ get_password_with_authmodule(User, Server) ->
|
||||
is_user_exists(User, Server) ->
|
||||
lists:any(
|
||||
fun(M) ->
|
||||
case M:is_user_exists(User, Server) of
|
||||
{error, Error} ->
|
||||
?ERROR_MSG("The authentication module ~p returned an "
|
||||
"error~nwhen checking user ~p in server ~p~n"
|
||||
"Error message: ~p",
|
||||
[M, User, Server, Error]),
|
||||
false;
|
||||
Else ->
|
||||
Else
|
||||
end
|
||||
M:is_user_exists(User, Server)
|
||||
end, auth_modules(Server)).
|
||||
|
||||
%% Check if the user exists in all authentications module except the module
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%%% Created : 17 Feb 2006 by Mickael Remond <mremond@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -79,7 +79,7 @@ allow_anonymous(Host) ->
|
||||
%% anonymous protocol can be: sasl_anon|login_anon|both
|
||||
is_sasl_anonymous_enabled(Host) ->
|
||||
case allow_anonymous(Host) of
|
||||
false -> false;
|
||||
false -> false;
|
||||
true ->
|
||||
case anonymous_protocol(Host) of
|
||||
sasl_anon -> true;
|
||||
@@ -97,7 +97,7 @@ is_login_anonymous_enabled(Host) ->
|
||||
true ->
|
||||
case anonymous_protocol(Host) of
|
||||
login_anon -> true;
|
||||
both -> true;
|
||||
both -> true;
|
||||
_Other -> false
|
||||
end
|
||||
end.
|
||||
@@ -115,8 +115,10 @@ anonymous_protocol(Host) ->
|
||||
%% Return true if multiple connections have been allowed in the config file
|
||||
%% defaults to false
|
||||
allow_multiple_connections(Host) ->
|
||||
ejabberd_config:get_local_option(
|
||||
{allow_multiple_connections, Host}) =:= true.
|
||||
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) ->
|
||||
@@ -174,7 +176,7 @@ check_password(User, Server, Password) ->
|
||||
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,
|
||||
case ejabberd_auth:is_user_exists_in_other_modules(?MODULE,
|
||||
User, Server) of
|
||||
%% If user exists in other module, reject anonnymous authentication
|
||||
true -> false;
|
||||
@@ -246,3 +248,4 @@ remove_user(_User, _Server, _Password) ->
|
||||
|
||||
plain_password_required() ->
|
||||
false.
|
||||
|
||||
|
||||
+19
-224
@@ -5,7 +5,7 @@
|
||||
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -35,9 +35,6 @@
|
||||
try_register/3,
|
||||
dirty_get_registered_users/0,
|
||||
get_vh_registered_users/1,
|
||||
get_vh_registered_users/2,
|
||||
get_vh_registered_users_number/1,
|
||||
get_vh_registered_users_number/2,
|
||||
get_password/2,
|
||||
get_password_s/2,
|
||||
is_user_exists/2,
|
||||
@@ -46,87 +43,45 @@
|
||||
plain_password_required/0
|
||||
]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% API
|
||||
%%%----------------------------------------------------------------------
|
||||
start(Host) ->
|
||||
extauth:start(
|
||||
Host, ejabberd_config:get_local_option({extauth_program, Host})),
|
||||
case check_cache_last_options(Host) of
|
||||
cache ->
|
||||
ok = ejabberd_auth_internal:start(Host);
|
||||
no_cache ->
|
||||
ok
|
||||
end.
|
||||
|
||||
check_cache_last_options(Server) ->
|
||||
%% if extauth_cache is enabled, then a mod_last module must also be enabled
|
||||
case get_cache_option(Server) of
|
||||
false -> no_cache;
|
||||
{true, _CacheTime} ->
|
||||
case get_mod_last_enabled(Server) of
|
||||
no_mod_last ->
|
||||
?ERROR_MSG("In host ~p extauth is used, extauth_cache is enabled but "
|
||||
"mod_last is not enabled.", [Server]),
|
||||
no_cache;
|
||||
_ -> cache
|
||||
end
|
||||
end.
|
||||
ok.
|
||||
|
||||
plain_password_required() ->
|
||||
true.
|
||||
|
||||
check_password(User, Server, Password) ->
|
||||
case get_cache_option(Server) of
|
||||
false -> check_password_extauth(User, Server, Password);
|
||||
{true, CacheTime} -> check_password_cache(User, Server, Password, CacheTime)
|
||||
end.
|
||||
extauth:check_password(User, Server, Password) andalso Password /= "".
|
||||
|
||||
check_password(User, Server, Password, _Digest, _DigestGen) ->
|
||||
check_password(User, Server, Password).
|
||||
|
||||
set_password(User, Server, Password) ->
|
||||
case extauth:set_password(User, Server, Password) of
|
||||
true -> set_password_internal(User, Server, Password),
|
||||
ok;
|
||||
true -> ok;
|
||||
_ -> {error, unknown_problem}
|
||||
end.
|
||||
|
||||
try_register(User, Server, Password) ->
|
||||
case get_cache_option(Server) of
|
||||
false -> try_register_extauth(User, Server, Password);
|
||||
{true, _CacheTime} -> try_register_external_cache(User, Server, Password)
|
||||
end.
|
||||
try_register(_User, _Server, _Password) ->
|
||||
{error, not_allowed}.
|
||||
|
||||
%% TODO
|
||||
%% Return the list of all users handled by external
|
||||
dirty_get_registered_users() ->
|
||||
ejabberd_auth_internal:dirty_get_registered_users().
|
||||
[].
|
||||
|
||||
get_vh_registered_users(Server) ->
|
||||
ejabberd_auth_internal:get_vh_registered_users(Server).
|
||||
get_vh_registered_users(_Server) ->
|
||||
[].
|
||||
|
||||
get_vh_registered_users(Server, Data) ->
|
||||
ejabberd_auth_internal:get_vh_registered_users(Server, Data).
|
||||
get_password(_User, _Server) ->
|
||||
false.
|
||||
|
||||
get_vh_registered_users_number(Server) ->
|
||||
ejabberd_auth_internal:get_vh_registered_users_number(Server).
|
||||
|
||||
get_vh_registered_users_number(Server, Data) ->
|
||||
ejabberd_auth_internal:get_vh_registered_users_number(Server, Data).
|
||||
|
||||
%% The password can only be returned if cache is enabled, cached info exists and is fresh enough.
|
||||
get_password(User, Server) ->
|
||||
case get_cache_option(Server) of
|
||||
false -> false;
|
||||
{true, CacheTime} -> get_password_cache(User, Server, CacheTime)
|
||||
end.
|
||||
|
||||
get_password_s(User, Server) ->
|
||||
case get_password(User, Server) of
|
||||
false -> [];
|
||||
Other -> Other
|
||||
end.
|
||||
get_password_s(_User, _Server) ->
|
||||
"".
|
||||
|
||||
%% @spec (User, Server) -> true | false | {error, Error}
|
||||
is_user_exists(User, Server) ->
|
||||
@@ -136,169 +91,9 @@ is_user_exists(User, Server) ->
|
||||
_:Error -> {error, Error}
|
||||
end.
|
||||
|
||||
remove_user(User, Server) ->
|
||||
case extauth:remove_user(User, Server) of
|
||||
false -> false;
|
||||
true ->
|
||||
case get_cache_option(Server) of
|
||||
false -> false;
|
||||
{true, _CacheTime} ->
|
||||
ejabberd_auth_internal:remove_user(User, Server)
|
||||
end
|
||||
end.
|
||||
remove_user(_User, _Server) ->
|
||||
{error, not_allowed}.
|
||||
|
||||
remove_user(User, Server, Password) ->
|
||||
case extauth:remove_user(User, Server, Password) of
|
||||
false -> false;
|
||||
true ->
|
||||
case get_cache_option(Server) of
|
||||
false -> false;
|
||||
{true, _CacheTime} ->
|
||||
ejabberd_auth_internal:remove_user(User, Server, Password)
|
||||
end
|
||||
end.
|
||||
remove_user(_User, _Server, _Password) ->
|
||||
not_allowed.
|
||||
|
||||
%%%
|
||||
%%% Extauth cache management
|
||||
%%%
|
||||
|
||||
%% @spec (Host::string()) -> false | {true, CacheTime::integer()}
|
||||
get_cache_option(Host) ->
|
||||
case ejabberd_config:get_local_option({extauth_cache, Host}) of
|
||||
CacheTime when is_integer(CacheTime) -> {true, CacheTime};
|
||||
_ -> false
|
||||
end.
|
||||
|
||||
%% @spec (User, Server, Password) -> true | false
|
||||
check_password_extauth(User, Server, Password) ->
|
||||
extauth:check_password(User, Server, Password) andalso Password /= "".
|
||||
|
||||
%% @spec (User, Server, Password) -> true | false
|
||||
try_register_extauth(User, Server, Password) ->
|
||||
extauth:try_register(User, Server, Password).
|
||||
|
||||
check_password_cache(User, Server, Password, CacheTime) ->
|
||||
case get_last_access(User, Server) of
|
||||
online ->
|
||||
check_password_internal(User, Server, Password);
|
||||
never ->
|
||||
check_password_external_cache(User, Server, Password);
|
||||
mod_last_required ->
|
||||
?ERROR_MSG("extauth is used, extauth_cache is enabled but mod_last is not enabled in that host", []),
|
||||
check_password_external_cache(User, Server, Password);
|
||||
TimeStamp ->
|
||||
%% If last access exists, compare last access with cache refresh time
|
||||
case is_fresh_enough(TimeStamp, CacheTime) of
|
||||
%% If no need to refresh, check password against Mnesia
|
||||
true ->
|
||||
case check_password_internal(User, Server, Password) of
|
||||
%% If password valid in Mnesia, accept it
|
||||
true ->
|
||||
true;
|
||||
%% Else (password nonvalid in Mnesia), check in extauth and cache result
|
||||
false ->
|
||||
check_password_external_cache(User, Server, Password)
|
||||
end;
|
||||
%% Else (need to refresh), check in extauth and cache result
|
||||
false ->
|
||||
check_password_external_cache(User, Server, Password)
|
||||
end
|
||||
end.
|
||||
|
||||
get_password_internal(User, Server) ->
|
||||
ejabberd_auth_internal:get_password(User, Server).
|
||||
|
||||
%% @spec (User, Server, CacheTime) -> false | Password::string()
|
||||
get_password_cache(User, Server, CacheTime) ->
|
||||
case get_last_access(User, Server) of
|
||||
online ->
|
||||
get_password_internal(User, Server);
|
||||
never ->
|
||||
false;
|
||||
mod_last_required ->
|
||||
?ERROR_MSG("extauth is used, extauth_cache is enabled but mod_last is not enabled in that host", []),
|
||||
false;
|
||||
TimeStamp ->
|
||||
case is_fresh_enough(TimeStamp, CacheTime) of
|
||||
true ->
|
||||
get_password_internal(User, Server);
|
||||
false ->
|
||||
false
|
||||
end
|
||||
end.
|
||||
|
||||
|
||||
%% Check the password using extauth; if success then cache it
|
||||
check_password_external_cache(User, Server, Password) ->
|
||||
case check_password_extauth(User, Server, Password) of
|
||||
true ->
|
||||
set_password_internal(User, Server, Password), true;
|
||||
false ->
|
||||
false
|
||||
end.
|
||||
|
||||
%% Try to register using extauth; if success then cache it
|
||||
try_register_external_cache(User, Server, Password) ->
|
||||
case try_register_extauth(User, Server, Password) of
|
||||
{atomic, ok} = R ->
|
||||
set_password_internal(User, Server, Password),
|
||||
R;
|
||||
_ -> {error, not_allowed}
|
||||
end.
|
||||
|
||||
%% @spec (User, Server, Password) -> true | false
|
||||
check_password_internal(User, Server, Password) ->
|
||||
ejabberd_auth_internal:check_password(User, Server, Password).
|
||||
|
||||
%% @spec (User, Server, Password) -> ok | {error, invalid_jid}
|
||||
set_password_internal(User, Server, Password) ->
|
||||
ejabberd_auth_internal:set_password(User, Server, Password).
|
||||
|
||||
%% @spec (TimeLast, CacheTime) -> true | false
|
||||
%% TimeLast = online | never | integer()
|
||||
%% CacheTime = integer() | false
|
||||
is_fresh_enough(online, _CacheTime) ->
|
||||
true;
|
||||
is_fresh_enough(never, _CacheTime) ->
|
||||
false;
|
||||
is_fresh_enough(TimeStampLast, CacheTime) ->
|
||||
{MegaSecs, Secs, _MicroSecs} = now(),
|
||||
Now = MegaSecs * 1000000 + Secs,
|
||||
(TimeStampLast + CacheTime > Now).
|
||||
|
||||
%% @spec (User, Server) -> online | never | mod_last_required | TimeStamp::integer()
|
||||
%% Code copied from mod_configure.erl
|
||||
%% Code copied from web/ejabberd_web_admin.erl
|
||||
%% TODO: Update time format to XEP-0202: Entity Time
|
||||
get_last_access(User, Server) ->
|
||||
case ejabberd_sm:get_user_resources(User, Server) of
|
||||
[] ->
|
||||
_US = {User, Server},
|
||||
case get_last_info(User, Server) of
|
||||
mod_last_required ->
|
||||
mod_last_required;
|
||||
not_found ->
|
||||
never;
|
||||
{ok, Timestamp, _Status} ->
|
||||
Timestamp
|
||||
end;
|
||||
_ ->
|
||||
online
|
||||
end.
|
||||
%% @spec (User, Server) -> {ok, Timestamp, Status} | not_found | mod_last_required
|
||||
get_last_info(User, Server) ->
|
||||
case get_mod_last_enabled(Server) of
|
||||
mod_last -> mod_last:get_last_info(User, Server);
|
||||
mod_last_odbc -> mod_last_odbc:get_last_info(User, Server);
|
||||
mod_mod_last -> mod_last_required
|
||||
end.
|
||||
|
||||
%% @spec (Server) -> mod_last | mod_last_odbc | no_mod_last
|
||||
get_mod_last_enabled(Server) ->
|
||||
ML = lists:member(mod_last, gen_mod:loaded_modules(Server)),
|
||||
MLO = lists:member(mod_last_odbc, gen_mod:loaded_modules(Server)),
|
||||
case {ML, MLO} of
|
||||
{true, _} -> mod_last;
|
||||
{false, true} -> mod_last_odbc;
|
||||
{false, false} -> no_mod_last
|
||||
end.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -68,11 +68,7 @@ update_reg_users_counter_table(Server) ->
|
||||
Set = get_vh_registered_users(Server),
|
||||
Size = length(Set),
|
||||
LServer = jlib:nameprep(Server),
|
||||
F = fun() ->
|
||||
mnesia:write(#reg_users_counter{vhost = LServer,
|
||||
count = Size})
|
||||
end,
|
||||
mnesia:sync_dirty(F).
|
||||
set_vh_registered_users_counter(LServer, Size).
|
||||
|
||||
plain_password_required() ->
|
||||
false.
|
||||
@@ -141,9 +137,7 @@ try_register(User, Server, Password) ->
|
||||
[] ->
|
||||
mnesia:write(#passwd{us = US,
|
||||
password = Password}),
|
||||
mnesia:dirty_update_counter(
|
||||
reg_users_counter,
|
||||
LServer, 1),
|
||||
inc_vh_registered_users_counter(LServer),
|
||||
ok;
|
||||
[_E] ->
|
||||
exists
|
||||
@@ -230,6 +224,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).
|
||||
|
||||
get_password(User, Server) ->
|
||||
LUser = jlib:nodeprep(User),
|
||||
LServer = jlib:nameprep(Server),
|
||||
@@ -275,8 +303,7 @@ remove_user(User, Server) ->
|
||||
US = {LUser, LServer},
|
||||
F = fun() ->
|
||||
mnesia:delete({passwd, US}),
|
||||
mnesia:dirty_update_counter(reg_users_counter,
|
||||
LServer, -1)
|
||||
dec_vh_registered_users_counter(LServer)
|
||||
end,
|
||||
mnesia:transaction(F),
|
||||
ok.
|
||||
@@ -291,8 +318,7 @@ remove_user(User, Server, Password) ->
|
||||
case mnesia:read({passwd, US}) of
|
||||
[#passwd{password = Password}] ->
|
||||
mnesia:delete({passwd, US}),
|
||||
mnesia:dirty_update_counter(reg_users_counter,
|
||||
LServer, -1),
|
||||
dec_vh_registered_users_counter(LServer),
|
||||
ok;
|
||||
[_] ->
|
||||
not_allowed;
|
||||
|
||||
+26
-47
@@ -5,7 +5,7 @@
|
||||
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -66,7 +66,7 @@
|
||||
servers,
|
||||
backups,
|
||||
port,
|
||||
tls_options,
|
||||
encrypt,
|
||||
dn,
|
||||
password,
|
||||
base,
|
||||
@@ -119,19 +119,19 @@ terminate(_Reason, _State) ->
|
||||
init(Host) ->
|
||||
State = parse_options(Host),
|
||||
eldap_pool:start_link(State#state.eldap_id,
|
||||
State#state.servers,
|
||||
State#state.backups,
|
||||
State#state.port,
|
||||
State#state.dn,
|
||||
State#state.password,
|
||||
State#state.tls_options),
|
||||
State#state.servers,
|
||||
State#state.backups,
|
||||
State#state.port,
|
||||
State#state.dn,
|
||||
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.tls_options),
|
||||
State#state.servers,
|
||||
State#state.backups,
|
||||
State#state.port,
|
||||
State#state.dn,
|
||||
State#state.password,
|
||||
State#state.encrypt),
|
||||
{ok, State}.
|
||||
|
||||
plain_password_required() ->
|
||||
@@ -153,14 +153,8 @@ check_password(User, Server, Password) ->
|
||||
check_password(User, Server, Password, _Digest, _DigestGen) ->
|
||||
check_password(User, Server, Password).
|
||||
|
||||
set_password(User, Server, Password) ->
|
||||
{ok, State} = eldap_utils:get_state(Server, ?MODULE),
|
||||
case find_user_dn(User, State) of
|
||||
false ->
|
||||
{error, user_not_found};
|
||||
DN ->
|
||||
eldap_pool:modify_passwd(State#state.eldap_id, DN, Password)
|
||||
end.
|
||||
set_password(_User, _Server, _Password) ->
|
||||
{error, not_allowed}.
|
||||
|
||||
%% @spec (User, Server, Password) -> {error, not_allowed}
|
||||
try_register(_User, _Server, _Password) ->
|
||||
@@ -223,13 +217,13 @@ get_vh_registered_users_ldap(Server) ->
|
||||
UIDs = State#state.uids,
|
||||
Eldap_ID = State#state.eldap_id,
|
||||
Server = State#state.host,
|
||||
ResAttrs = result_attrs(State),
|
||||
SortedDNAttrs = eldap_utils:usort_attrs(State#state.dn_filter_attrs),
|
||||
case eldap_filter:parse(State#state.sfilter) of
|
||||
{ok, EldapFilter} ->
|
||||
case eldap_pool:search(Eldap_ID, [{base, State#state.base},
|
||||
{filter, EldapFilter},
|
||||
{timeout, ?LDAP_SEARCH_TIMEOUT},
|
||||
{attributes, ResAttrs}]) of
|
||||
{attributes, SortedDNAttrs}]) of
|
||||
#eldap_search_result{entries = Entries} ->
|
||||
lists:flatmap(
|
||||
fun(#eldap_entry{attributes = Attrs,
|
||||
@@ -275,16 +269,15 @@ handle_call(_Request, _From, State) ->
|
||||
{reply, bad_request, State}.
|
||||
|
||||
find_user_dn(User, State) ->
|
||||
ResAttrs = result_attrs(State),
|
||||
DNAttrs = eldap_utils:usort_attrs(State#state.dn_filter_attrs),
|
||||
case eldap_filter:parse(State#state.ufilter, [{"%u", User}]) of
|
||||
{ok, Filter} ->
|
||||
case eldap_pool:search(State#state.eldap_id,
|
||||
[{base, State#state.base},
|
||||
{filter, Filter},
|
||||
{attributes, ResAttrs}]) of
|
||||
case eldap_pool:search(State#state.eldap_id, [{base, State#state.base},
|
||||
{filter, Filter},
|
||||
{attributes, DNAttrs}]) of
|
||||
#eldap_search_result{entries = [#eldap_entry{attributes = Attrs,
|
||||
object_name = DN} | _]} ->
|
||||
dn_filter(DN, Attrs, State);
|
||||
dn_filter(DN, Attrs, State);
|
||||
_ ->
|
||||
false
|
||||
end;
|
||||
@@ -353,14 +346,6 @@ local_filter(equal, Attrs, FilterMatch) ->
|
||||
local_filter(notequal, Attrs, FilterMatch) ->
|
||||
not local_filter(equal, Attrs, FilterMatch).
|
||||
|
||||
result_attrs(#state{uids = UIDs, dn_filter_attrs = DNFilterAttrs}) ->
|
||||
lists:foldl(
|
||||
fun({UID}, Acc) ->
|
||||
[UID | Acc];
|
||||
({UID, _}, Acc) ->
|
||||
[UID | Acc]
|
||||
end, DNFilterAttrs, UIDs).
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% Auxiliary functions
|
||||
%%%----------------------------------------------------------------------
|
||||
@@ -373,7 +358,6 @@ parse_options(Host) ->
|
||||
Backups -> Backups
|
||||
end,
|
||||
LDAPEncrypt = ejabberd_config:get_local_option({ldap_encrypt, Host}),
|
||||
LDAPTLSVerify = ejabberd_config:get_local_option({ldap_tls_verify, Host}),
|
||||
LDAPPort = case ejabberd_config:get_local_option({ldap_port, Host}) of
|
||||
undefined -> case LDAPEncrypt of
|
||||
tls -> ?LDAPS_PORT;
|
||||
@@ -404,12 +388,8 @@ parse_options(Host) ->
|
||||
LDAPBase = ejabberd_config:get_local_option({ldap_base, Host}),
|
||||
{DNFilter, DNFilterAttrs} =
|
||||
case ejabberd_config:get_local_option({ldap_dn_filter, Host}) of
|
||||
undefined ->
|
||||
{undefined, []};
|
||||
{DNF, undefined} ->
|
||||
{DNF, []};
|
||||
{DNF, DNFA} ->
|
||||
{DNF, DNFA}
|
||||
undefined -> {undefined, undefined};
|
||||
{DNF, DNFA} -> {DNF, DNFA}
|
||||
end,
|
||||
LocalFilter = ejabberd_config:get_local_option({ldap_local_filter, Host}),
|
||||
#state{host = Host,
|
||||
@@ -418,8 +398,7 @@ parse_options(Host) ->
|
||||
servers = LDAPServers,
|
||||
backups = LDAPBackups,
|
||||
port = LDAPPort,
|
||||
tls_options = [{encrypt, LDAPEncrypt},
|
||||
{tls_verify, LDAPTLSVerify}],
|
||||
encrypt = LDAPEncrypt,
|
||||
dn = RootDN,
|
||||
password = Password,
|
||||
base = LDAPBase,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%%% Created : 5 Jul 2007 by Evgeniy Khramtsov <xram@jabber.ru>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -60,11 +60,7 @@ check_password(User, Server, Password, _Digest, _DigestGen) ->
|
||||
|
||||
check_password(User, Host, Password) ->
|
||||
Service = get_pam_service(Host),
|
||||
UserInfo = case get_pam_userinfotype(Host) of
|
||||
username -> User;
|
||||
jid -> User++"@"++Host
|
||||
end,
|
||||
case catch epam:authenticate(Service, UserInfo, Password) of
|
||||
case catch epam:authenticate(Service, User, Password) of
|
||||
true -> true;
|
||||
_ -> false
|
||||
end.
|
||||
@@ -88,11 +84,7 @@ get_password_s(_User, _Server) ->
|
||||
%% TODO: Improve this function to return an error instead of 'false' when connection to PAM failed
|
||||
is_user_exists(User, Host) ->
|
||||
Service = get_pam_service(Host),
|
||||
UserInfo = case get_pam_userinfotype(Host) of
|
||||
username -> User;
|
||||
jid -> User++"@"++Host
|
||||
end,
|
||||
case catch epam:acct_mgmt(Service, UserInfo) of
|
||||
case catch epam:acct_mgmt(Service, User) of
|
||||
true -> true;
|
||||
_ -> false
|
||||
end.
|
||||
@@ -114,8 +106,3 @@ get_pam_service(Host) ->
|
||||
undefined -> "ejabberd";
|
||||
Service -> Service
|
||||
end.
|
||||
get_pam_userinfotype(Host) ->
|
||||
case ejabberd_config:get_local_option({pam_userinfotype, Host}) of
|
||||
undefined -> username;
|
||||
Type -> Type
|
||||
end.
|
||||
|
||||
+33
-139
@@ -5,7 +5,7 @@
|
||||
%%% Created : 16 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -28,9 +28,7 @@
|
||||
-author('alexey@process-one.net').
|
||||
-update_info({update, 0}).
|
||||
|
||||
-define(GEN_FSM, p1_fsm).
|
||||
|
||||
-behaviour(?GEN_FSM).
|
||||
-behaviour(gen_fsm).
|
||||
|
||||
%% External exports
|
||||
-export([start/2,
|
||||
@@ -55,9 +53,7 @@
|
||||
handle_sync_event/4,
|
||||
code_change/4,
|
||||
handle_info/3,
|
||||
terminate/3,
|
||||
print_state/1
|
||||
]).
|
||||
terminate/3]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("jlib.hrl").
|
||||
@@ -108,8 +104,8 @@
|
||||
|
||||
%% Module start with or without supervisor:
|
||||
-ifdef(NO_TRANSIENT_SUPERVISORS).
|
||||
-define(SUPERVISOR_START, ?GEN_FSM:start(ejabberd_c2s, [SockData, Opts],
|
||||
fsm_limit_opts(Opts) ++ ?FSMOPTS)).
|
||||
-define(SUPERVISOR_START, gen_fsm:start(ejabberd_c2s, [SockData, Opts],
|
||||
?FSMOPTS)).
|
||||
-else.
|
||||
-define(SUPERVISOR_START, supervisor:start_child(ejabberd_c2s_sup,
|
||||
[SockData, Opts])).
|
||||
@@ -144,18 +140,17 @@ start(SockData, Opts) ->
|
||||
?SUPERVISOR_START.
|
||||
|
||||
start_link(SockData, Opts) ->
|
||||
?GEN_FSM:start_link(ejabberd_c2s, [SockData, Opts],
|
||||
fsm_limit_opts(Opts) ++ ?FSMOPTS).
|
||||
gen_fsm:start_link(ejabberd_c2s, [SockData, Opts], ?FSMOPTS).
|
||||
|
||||
socket_type() ->
|
||||
xml_stream.
|
||||
|
||||
%% Return Username, Resource and presence information
|
||||
get_presence(FsmRef) ->
|
||||
?GEN_FSM:sync_send_all_state_event(FsmRef, {get_presence}, 1000).
|
||||
gen_fsm:sync_send_all_state_event(FsmRef, {get_presence}, 1000).
|
||||
|
||||
stop(FsmRef) ->
|
||||
?GEN_FSM:send_event(FsmRef, closed).
|
||||
gen_fsm:send_event(FsmRef, closed).
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% Callback functions from gen_fsm
|
||||
@@ -192,6 +187,7 @@ init([{SockMod, Socket}, Opts]) ->
|
||||
(_) -> false
|
||||
end, Opts),
|
||||
TLSOpts = [verify_none | TLSOpts1],
|
||||
Zlib = lists:member(zlib, Opts) andalso (not StartTLSRequired),
|
||||
IP = peerip(SockMod, Socket),
|
||||
%% Check if IP is blacklisted:
|
||||
case is_ip_blacklisted(IP) of
|
||||
@@ -226,7 +222,7 @@ init([{SockMod, Socket}, Opts]) ->
|
||||
|
||||
%% Return list of all available resources of contacts,
|
||||
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).
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: StateName/2
|
||||
@@ -317,10 +313,10 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
||||
[{xmlelement, "mechanisms",
|
||||
[{"xmlns", ?NS_SASL}],
|
||||
Mechs}] ++
|
||||
ejabberd_hooks:run_fold(
|
||||
c2s_stream_features,
|
||||
Server,
|
||||
[], [Server])}),
|
||||
ejabberd_hooks:run_fold(
|
||||
c2s_stream_features,
|
||||
Server,
|
||||
[], [])}),
|
||||
fsm_next_state(wait_for_feature_request,
|
||||
StateData#state{
|
||||
server = Server,
|
||||
@@ -329,20 +325,11 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
||||
_ ->
|
||||
case StateData#state.resource of
|
||||
"" ->
|
||||
RosterVersioningFeature =
|
||||
ejabberd_hooks:run_fold(
|
||||
roster_get_versioning_feature,
|
||||
Server, [], [Server]),
|
||||
StreamFeatures =
|
||||
[{xmlelement, "bind",
|
||||
[{"xmlns", ?NS_BIND}], []},
|
||||
{xmlelement, "session",
|
||||
[{"xmlns", ?NS_SESSION}], []}]
|
||||
++ RosterVersioningFeature
|
||||
++ ejabberd_hooks:run_fold(
|
||||
c2s_stream_features,
|
||||
Server,
|
||||
[], [Server]),
|
||||
RosterVersioningFeature = ejabberd_hooks:run_fold(roster_get_versioning_feature, Server, [], [Server]),
|
||||
StreamFeatures = [{xmlelement, "bind",
|
||||
[{"xmlns", ?NS_BIND}], []},
|
||||
{xmlelement, "session",
|
||||
[{"xmlns", ?NS_SESSION}], []} | RosterVersioningFeature],
|
||||
send_element(
|
||||
StateData,
|
||||
{xmlelement, "stream:features", [],
|
||||
@@ -471,11 +458,11 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
|
||||
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),
|
||||
ejabberd_sm:open_session(
|
||||
SID, U, StateData#state.server, R, Info),
|
||||
change_shaper(StateData, JID),
|
||||
{Fs, Ts} = ejabberd_hooks:run_fold(
|
||||
roster_get_subscription_lists,
|
||||
@@ -787,15 +774,6 @@ wait_for_bind({xmlstreamelement, El}, StateData) ->
|
||||
fsm_next_state(wait_for_bind, StateData);
|
||||
_ ->
|
||||
JID = jlib:make_jid(U, StateData#state.server, R),
|
||||
%%Server = StateData#state.server,
|
||||
%%RosterVersioningFeature =
|
||||
%% ejabberd_hooks:run_fold(
|
||||
%% roster_get_versioning_feature, Server, [], [Server]),
|
||||
%%StreamFeatures = [{xmlelement, "session",
|
||||
%% [{"xmlns", ?NS_SESSION}], []} |
|
||||
%% RosterVersioningFeature],
|
||||
%%send_element(StateData, {xmlelement, "stream:features",
|
||||
%% [], StreamFeatures}),
|
||||
Res = IQ#iq{type = result,
|
||||
sub_el = [{xmlelement, "bind",
|
||||
[{"xmlns", ?NS_BIND}],
|
||||
@@ -839,6 +817,12 @@ wait_for_session({xmlstreamelement, El}, StateData) ->
|
||||
?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),
|
||||
@@ -855,12 +839,6 @@ wait_for_session({xmlstreamelement, El}, StateData) ->
|
||||
privacy_get_user_list, StateData#state.server,
|
||||
#userlist{},
|
||||
[U, StateData#state.server]),
|
||||
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),
|
||||
NewStateData =
|
||||
StateData#state{
|
||||
sid = SID,
|
||||
@@ -917,7 +895,7 @@ session_established({xmlstreamelement, El}, StateData) ->
|
||||
session_established(timeout, StateData) ->
|
||||
%% TODO: Options must be stored in state:
|
||||
Options = [],
|
||||
proc_lib:hibernate(?GEN_FSM, enter_loop,
|
||||
proc_lib:hibernate(gen_fsm, enter_loop,
|
||||
[?MODULE, Options, session_established, StateData]),
|
||||
fsm_next_state(session_established, StateData);
|
||||
|
||||
@@ -1242,7 +1220,7 @@ handle_info({route, From, To, Packet}, StateName, StateData) ->
|
||||
"iq" ->
|
||||
IQ = jlib:iq_query_info(Packet),
|
||||
case IQ of
|
||||
#iq{xmlns = ?NS_VCARD} when (To#jid.luser == "") or (To#jid.lresource == "") ->
|
||||
#iq{xmlns = ?NS_VCARD} ->
|
||||
Host = StateData#state.server,
|
||||
case ets:lookup(sm_iqtable, {?NS_VCARD, Host}) of
|
||||
[{_, Module, Function, Opts}] ->
|
||||
@@ -1284,19 +1262,7 @@ handle_info({route, From, To, Packet}, StateName, StateData) ->
|
||||
{From, To, Packet},
|
||||
in]) of
|
||||
allow ->
|
||||
case ejabberd_hooks:run_fold(
|
||||
feature_check_packet, StateData#state.server,
|
||||
allow,
|
||||
[StateData#state.jid,
|
||||
StateData#state.server,
|
||||
StateData#state.pres_last,
|
||||
{From, To, Packet},
|
||||
in]) of
|
||||
allow ->
|
||||
{true, Attrs, StateData};
|
||||
deny ->
|
||||
{false, Attrs, StateData}
|
||||
end;
|
||||
{true, Attrs, StateData};
|
||||
deny ->
|
||||
{false, Attrs, StateData}
|
||||
end;
|
||||
@@ -1328,55 +1294,10 @@ handle_info({route, From, To, Packet}, StateName, StateData) ->
|
||||
handle_info({'DOWN', Monitor, _Type, _Object, _Info}, _StateName, StateData)
|
||||
when Monitor == StateData#state.socket_monitor ->
|
||||
{stop, normal, StateData};
|
||||
handle_info(system_shutdown, StateName, StateData) ->
|
||||
case StateName of
|
||||
wait_for_stream ->
|
||||
send_header(StateData, ?MYNAME, "1.0", "en"),
|
||||
send_element(StateData, ?SERR_SYSTEM_SHUTDOWN),
|
||||
send_trailer(StateData),
|
||||
ok;
|
||||
_ ->
|
||||
send_element(StateData, ?SERR_SYSTEM_SHUTDOWN),
|
||||
send_trailer(StateData),
|
||||
ok
|
||||
end,
|
||||
{stop, normal, StateData};
|
||||
handle_info({force_update_presence, LUser}, StateName,
|
||||
#state{user = LUser, server = LServer} = StateData) ->
|
||||
NewStateData =
|
||||
case StateData#state.pres_last of
|
||||
{xmlelement, "presence", _Attrs, _Els} ->
|
||||
PresenceEl = ejabberd_hooks:run_fold(
|
||||
c2s_update_presence,
|
||||
LServer,
|
||||
StateData#state.pres_last,
|
||||
[LUser, LServer]),
|
||||
StateData2 = StateData#state{pres_last = PresenceEl},
|
||||
presence_update(StateData2#state.jid,
|
||||
PresenceEl,
|
||||
StateData2),
|
||||
StateData2;
|
||||
_ ->
|
||||
StateData
|
||||
end,
|
||||
{next_state, StateName, NewStateData};
|
||||
handle_info(Info, StateName, StateData) ->
|
||||
?ERROR_MSG("Unexpected info: ~p", [Info]),
|
||||
fsm_next_state(StateName, StateData).
|
||||
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: print_state/1
|
||||
%% Purpose: Prepare the state to be printed on error log
|
||||
%% Returns: State to print
|
||||
%%----------------------------------------------------------------------
|
||||
print_state(State = #state{pres_t = T, pres_f = F, pres_a = A, pres_i = I}) ->
|
||||
State#state{pres_t = {pres_t, ?SETS:size(T)},
|
||||
pres_f = {pres_f, ?SETS:size(F)},
|
||||
pres_a = {pres_a, ?SETS:size(A)},
|
||||
pres_i = {pres_i, ?SETS:size(I)}
|
||||
}.
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: terminate/3
|
||||
%% Purpose: Shutdown the fsm
|
||||
@@ -1435,8 +1356,7 @@ terminate(_Reason, StateName, StateData) ->
|
||||
presence_broadcast(
|
||||
StateData, From, StateData#state.pres_i, Packet)
|
||||
end
|
||||
end,
|
||||
bounce_messages();
|
||||
end;
|
||||
_ ->
|
||||
ok
|
||||
end,
|
||||
@@ -2081,12 +2001,8 @@ resend_offline_messages(#state{user = User,
|
||||
jlib:jid_to_string(From),
|
||||
jlib:jid_to_string(To),
|
||||
Attrs),
|
||||
FixedPacket = {xmlelement, Name, Attrs2, Els},
|
||||
send_element(StateData, FixedPacket),
|
||||
ejabberd_hooks:run(user_receive_packet,
|
||||
StateData#state.server,
|
||||
[StateData#state.jid,
|
||||
From, To, FixedPacket]);
|
||||
send_element(StateData,
|
||||
{xmlelement, Name, Attrs2, Els});
|
||||
true ->
|
||||
ok
|
||||
end
|
||||
@@ -2216,28 +2132,6 @@ check_from(El, FromJID) ->
|
||||
end
|
||||
end.
|
||||
|
||||
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.
|
||||
|
||||
bounce_messages() ->
|
||||
receive
|
||||
{route, From, To, El} ->
|
||||
ejabberd_router:route(From, To, El),
|
||||
bounce_messages()
|
||||
after 0 ->
|
||||
ok
|
||||
end.
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% JID Set memory footprint reduction code
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
%%% Created : 2 Nov 2007 by Mickael Remond <mremond@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%%% Created : 26 Apr 2008 by Evgeniy Khramtsov <xramtsov@gmail.com>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -328,9 +328,7 @@ get_prog_name() ->
|
||||
FileName when is_list(FileName) ->
|
||||
FileName;
|
||||
_ ->
|
||||
?DEBUG("The option captcha_cmd is not configured, but some "
|
||||
"module wants to use the CAPTCHA feature.", []),
|
||||
throw({error, option_not_configured_captcha_cmd})
|
||||
""
|
||||
end.
|
||||
|
||||
get_url(Str) ->
|
||||
@@ -390,10 +388,9 @@ return(Port, TRef, Result) ->
|
||||
Result.
|
||||
|
||||
is_feature_enabled() ->
|
||||
try get_prog_name() of
|
||||
case get_prog_name() of
|
||||
"" -> false;
|
||||
Prog when is_list(Prog) -> true
|
||||
catch
|
||||
_:_ -> false
|
||||
end.
|
||||
|
||||
is_feature_available() ->
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%%% Created : 27 Feb 2008 by Mickael Remond <mremond@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%%% Created : 20 May 2008 by Badlop <badlop@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -356,14 +356,15 @@ get_tags_commands() ->
|
||||
%% @doc Check access is allowed to that command.
|
||||
%% At least one AccessCommand must be satisfied.
|
||||
%% It may throw {error, Error} where:
|
||||
%% Error = account_unprivileged | invalid_account_data
|
||||
%% 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, Auth) of
|
||||
case check_access(Access, User, Server) of
|
||||
true ->
|
||||
check_access_command(Commands, Command, ArgumentRestrictions,
|
||||
Method, Arguments);
|
||||
@@ -378,7 +379,7 @@ check_access_commands(AccessCommands, Auth, Method, Command, Arguments) ->
|
||||
end.
|
||||
|
||||
check_auth(noauth) ->
|
||||
no_auth_provided;
|
||||
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),
|
||||
@@ -393,10 +394,7 @@ get_md5(AccountPass) ->
|
||||
lists:flatten([io_lib:format("~.16B", [X])
|
||||
|| X <- binary_to_list(crypto:md5(AccountPass))]).
|
||||
|
||||
check_access(all, _) ->
|
||||
true;
|
||||
check_access(Access, Auth) ->
|
||||
{ok, User, Server} = check_auth(Auth),
|
||||
check_access(Access, User, Server) ->
|
||||
%% Check this user has access permission
|
||||
case acl:match_rule(Server, Access, jlib:make_jid(User, Server, "")) of
|
||||
allow -> true;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
+9
-59
@@ -5,7 +5,7 @@
|
||||
%%% Created : 14 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -101,14 +101,15 @@ get_plain_terms_file(File1) ->
|
||||
case file:consult(File) of
|
||||
{ok, Terms} ->
|
||||
include_config_files(Terms);
|
||||
{error, {LineNumber, erl_parse, _ParseMessage} = Reason} ->
|
||||
ExitText = describe_config_problem(File, Reason, LineNumber),
|
||||
?ERROR_MSG(ExitText, []),
|
||||
exit_or_halt(ExitText);
|
||||
{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]),
|
||||
exit(ExitText);
|
||||
{error, Reason} ->
|
||||
ExitText = describe_config_problem(File, Reason),
|
||||
?ERROR_MSG(ExitText, []),
|
||||
exit_or_halt(ExitText)
|
||||
ExitText = lists:flatten(File ++ ": " ++ file:format_error(Reason)),
|
||||
?ERROR_MSG("Problem loading ejabberd config file ~n~s", [ExitText]),
|
||||
exit(ExitText)
|
||||
end.
|
||||
|
||||
%% @doc Convert configuration filename to absolute path.
|
||||
@@ -169,57 +170,6 @@ normalize_hosts([Host|Hosts], PrepHosts) ->
|
||||
end.
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%% Errors reading the config file
|
||||
|
||||
describe_config_problem(Filename, Reason) ->
|
||||
Text1 = lists:flatten("Problem loading ejabberd config file " ++ Filename),
|
||||
Text2 = lists:flatten(" : " ++ file:format_error(Reason)),
|
||||
ExitText = Text1 ++ Text2,
|
||||
ExitText.
|
||||
|
||||
describe_config_problem(Filename, Reason, LineNumber) ->
|
||||
Text1 = lists:flatten("Problem loading ejabberd config file " ++ Filename),
|
||||
Text2 = lists:flatten(" approximately in the line "
|
||||
++ file:format_error(Reason)),
|
||||
ExitText = Text1 ++ Text2,
|
||||
Lines = get_config_lines(Filename, LineNumber, 10, 3),
|
||||
?ERROR_MSG("The following lines from your configuration file might be"
|
||||
" relevant to the error: ~n~s", [Lines]),
|
||||
ExitText.
|
||||
|
||||
get_config_lines(Filename, TargetNumber, PreContext, PostContext) ->
|
||||
{ok, Fd} = file:open(Filename, [read]),
|
||||
LNumbers = lists:seq(TargetNumber-PreContext, TargetNumber+PostContext),
|
||||
NextL = io:get_line(Fd, no_prompt),
|
||||
R = get_config_lines2(Fd, NextL, 1, LNumbers, []),
|
||||
file:close(Fd),
|
||||
R.
|
||||
|
||||
get_config_lines2(_Fd, eof, _CurrLine, _LNumbers, R) ->
|
||||
lists:reverse(R);
|
||||
get_config_lines2(_Fd, _NewLine, _CurrLine, [], R) ->
|
||||
lists:reverse(R);
|
||||
get_config_lines2(Fd, Data, CurrLine, [NextWanted | LNumbers], R) when is_list(Data) ->
|
||||
NextL = io:get_line(Fd, no_prompt),
|
||||
if
|
||||
CurrLine >= NextWanted ->
|
||||
Line2 = [integer_to_list(CurrLine), ": " | Data],
|
||||
get_config_lines2(Fd, NextL, CurrLine+1, LNumbers, [Line2 | R]);
|
||||
true ->
|
||||
get_config_lines2(Fd, NextL, CurrLine+1, [NextWanted | LNumbers], R)
|
||||
end.
|
||||
|
||||
%% If ejabberd isn't yet running in this node, then halt the node
|
||||
exit_or_halt(ExitText) ->
|
||||
case [Vsn || {ejabberd, _Desc, Vsn} <- application:which_applications()] of
|
||||
[] ->
|
||||
timer:sleep(1000),
|
||||
halt(ExitText);
|
||||
[_] ->
|
||||
exit(ExitText)
|
||||
end.
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%% Support for 'include_config_file'
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
+14
-20
@@ -5,7 +5,7 @@
|
||||
%%% Created : 11 Jan 2004 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -189,21 +189,16 @@ process(["help" | Mode]) ->
|
||||
["help"] ->
|
||||
print_usage_help(MaxC, ShCode),
|
||||
?STATUS_SUCCESS;
|
||||
[CmdString | _] ->
|
||||
{ok, CmdStringU, _} = regexp:gsub(CmdString, "-", "_"),
|
||||
print_usage_commands(CmdStringU, MaxC, ShCode),
|
||||
[CommandString | _] ->
|
||||
print_usage_commands(CommandString, MaxC, ShCode),
|
||||
?STATUS_SUCCESS
|
||||
end;
|
||||
|
||||
process(Args) ->
|
||||
AccessCommands = get_accesscommands(),
|
||||
{String, Code} = process2(Args, AccessCommands),
|
||||
case String of
|
||||
[] -> ok;
|
||||
_ ->
|
||||
io:format(String),
|
||||
io:format("\n")
|
||||
end,
|
||||
io:format(String),
|
||||
io:format("\n"),
|
||||
Code.
|
||||
|
||||
%% @spec (Args::[string()], AccessCommands) -> {String::string(), Code::integer()}
|
||||
@@ -319,19 +314,18 @@ format_args(Args, ArgsFormat) ->
|
||||
[],
|
||||
lists:zip(ArgsFormat, Args)).
|
||||
|
||||
format_arg(Arg, integer) ->
|
||||
format_arg2(Arg, "~d");
|
||||
format_arg("", string) ->
|
||||
"";
|
||||
format_arg(Arg, string) ->
|
||||
NumChars = integer_to_list(string:len(Arg)),
|
||||
Parse = "~" ++ NumChars ++ "c",
|
||||
format_arg2(Arg, Parse).
|
||||
|
||||
format_arg2(Arg, Parse)->
|
||||
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
|
||||
%%-----------------------------
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%%% Created : 6 may 2009 by Mickael Remond <mremond@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%%% Created : 23 Aug 2006 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%%% Created : 8 Aug 2004 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%%% Created : 16 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -31,7 +31,6 @@
|
||||
init/3,
|
||||
start_listeners/0,
|
||||
start_listener/3,
|
||||
stop_listeners/0,
|
||||
stop_listener/2,
|
||||
parse_listener_portip/2,
|
||||
add_listener/3,
|
||||
@@ -128,12 +127,10 @@ init_udp(PortIP, Module, Opts, SockOpts, Port, IPS) ->
|
||||
end.
|
||||
|
||||
init_tcp(PortIP, Module, Opts, SockOpts, Port, IPS) ->
|
||||
SockOpts2 = try erlang:system_info(otp_release) >= "R13B" of
|
||||
true -> [{send_timeout_close, true} | SockOpts];
|
||||
false -> SockOpts
|
||||
catch
|
||||
_:_ -> []
|
||||
end,
|
||||
SockOpts2 = case erlang:system_info(otp_release) >= "R13B" of
|
||||
true -> [{send_timeout_close, true} | SockOpts];
|
||||
false -> SockOpts
|
||||
end,
|
||||
Res = gen_tcp:listen(Port, [binary,
|
||||
{packet, 0},
|
||||
{active, false},
|
||||
@@ -307,14 +304,6 @@ start_listener_sup(Port, Module, Opts) ->
|
||||
[?MODULE]},
|
||||
supervisor:start_child(ejabberd_listeners, ChildSpec).
|
||||
|
||||
stop_listeners() ->
|
||||
Ports = ejabberd_config:get_local_option(listen),
|
||||
lists:foreach(
|
||||
fun({PortIpNetp, Module, _Opts}) ->
|
||||
delete_listener(PortIpNetp, Module)
|
||||
end,
|
||||
Ports).
|
||||
|
||||
%% @spec (PortIP, Module) -> ok
|
||||
%% where
|
||||
%% PortIP = {Port, IPT | IPS}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%%% Created : 30 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%%% Created : 23 Oct 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
%%% Created : 29 Nov 2006 by Mickael Remond <mremond@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%%% Created : 1 Nov 2006 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
+12
-24
@@ -5,7 +5,7 @@
|
||||
%%% Created : 17 Jul 2008 by Pablo Polvorin <pablo.polvorin@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -212,7 +212,7 @@ add_user(El, Domain, User, Password) ->
|
||||
El),
|
||||
ok;
|
||||
{atomic, exists} ->
|
||||
io:format("Account ~s@~s already exists, updating it...~n",
|
||||
?INFO_MSG("User ~p@~p already exists, using stored profile...~n",
|
||||
[User, Domain]),
|
||||
io:format(""),
|
||||
ok = exmpp_xml:foreach(
|
||||
@@ -417,10 +417,10 @@ to_list(B) when is_atom(B) -> atom_to_list(B).
|
||||
|
||||
%%%==================================
|
||||
|
||||
%%%% Export hosts
|
||||
%%%% Export server
|
||||
|
||||
%% @spec (Dir::string(), Hosts::[string()]) -> ok
|
||||
export_hosts(Dir, Hosts) ->
|
||||
%% @spec (Dir::string()) -> ok
|
||||
export_server(Dir) ->
|
||||
try_start_exmpp(),
|
||||
|
||||
FnT = make_filename_template(),
|
||||
@@ -430,6 +430,7 @@ export_hosts(Dir, Hosts) ->
|
||||
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],
|
||||
|
||||
@@ -441,21 +442,15 @@ export_hosts(Dir, Hosts) ->
|
||||
|
||||
ok.
|
||||
|
||||
%%%==================================
|
||||
%%%% Export server
|
||||
|
||||
%% @spec (Dir::string()) -> ok
|
||||
export_server(Dir) ->
|
||||
Hosts = ?MYHOSTS,
|
||||
export_hosts(Dir, Hosts).
|
||||
|
||||
%%%==================================
|
||||
%%%% Export host
|
||||
|
||||
%% @spec (Dir::string(), Host::string()) -> ok
|
||||
export_host(Dir, Host) ->
|
||||
Hosts = [Host],
|
||||
export_hosts(Dir, Hosts).
|
||||
try_start_exmpp(),
|
||||
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) ->
|
||||
@@ -468,7 +463,6 @@ export_host(Dir, FnH, Host) ->
|
||||
|
||||
Users = ejabberd_auth:get_vh_registered_users(Host),
|
||||
[export_user(Fd, Username, Host) || {Username, _Host} <- Users],
|
||||
timer:sleep(500), % Delay to ensure ERROR_MSG are displayed in the shell
|
||||
|
||||
print(Fd, make_piefxis_host_tail()),
|
||||
print(Fd, make_piefxis_xml_tail()),
|
||||
@@ -517,14 +511,8 @@ make_xinclude(Fn) ->
|
||||
%% @spec (Fd, Username::string(), Host::string()) -> ok
|
||||
%% @doc Extract user information and print it.
|
||||
export_user(Fd, Username, Host) ->
|
||||
try extract_user(Username, Host) of
|
||||
UserString ->
|
||||
print(Fd, UserString)
|
||||
catch
|
||||
E1:E2 ->
|
||||
?ERROR_MSG("The account ~s@~s is not exported because a problem "
|
||||
"was found in it:~n~p: ~p", [Username, Host, E1, E2])
|
||||
end.
|
||||
UserString = extract_user(Username, Host),
|
||||
print(Fd, UserString).
|
||||
|
||||
%% @spec (Username::string(), Host::string()) -> string()
|
||||
extract_user(Username, Host) ->
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%%% Created : 31 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%%% Created : 10 Nov 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
+2
-14
@@ -5,7 +5,7 @@
|
||||
%%% Created : 27 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -31,7 +31,6 @@
|
||||
|
||||
%% API
|
||||
-export([route/3,
|
||||
route_error/4,
|
||||
register_route/1,
|
||||
register_route/2,
|
||||
register_routes/1,
|
||||
@@ -73,17 +72,6 @@ route(From, To, Packet) ->
|
||||
ok
|
||||
end.
|
||||
|
||||
%% Route the error packet only if the originating packet is not an error itself.
|
||||
%% RFC3920 9.3.1
|
||||
route_error(From, To, ErrPacket, OrigPacket) ->
|
||||
{xmlelement, _Name, Attrs, _Els} = OrigPacket,
|
||||
case "error" == xml:get_attr_s("type", Attrs) of
|
||||
false ->
|
||||
route(From, To, ErrPacket);
|
||||
true ->
|
||||
ok
|
||||
end.
|
||||
|
||||
register_route(Domain) ->
|
||||
register_route(Domain, undefined).
|
||||
|
||||
@@ -103,7 +91,7 @@ register_route(Domain, LocalHint) ->
|
||||
mnesia:transaction(F);
|
||||
N ->
|
||||
F = fun() ->
|
||||
case mnesia:wread({route, LDomain}) of
|
||||
case mnesia:read({route, LDomain}) of
|
||||
[] ->
|
||||
mnesia:write(
|
||||
#route{domain = LDomain,
|
||||
|
||||
+11
-27
@@ -5,7 +5,7 @@
|
||||
%%% Created : 7 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -245,7 +245,7 @@ clean_table_from_bad_node(Node) ->
|
||||
mnesia:delete_object(E)
|
||||
end, Es)
|
||||
end,
|
||||
mnesia:async_dirty(F).
|
||||
mnesia:transaction(F).
|
||||
|
||||
do_route(From, To, Packet) ->
|
||||
?DEBUG("s2s manager~n\tfrom ~p~n\tto ~p~n\tpacket ~P~n",
|
||||
@@ -486,31 +486,15 @@ update_tables() ->
|
||||
|
||||
%% Check if host is in blacklist or white list
|
||||
allow_host(MyServer, S2SHost) ->
|
||||
case lists:filter(
|
||||
fun(Host) ->
|
||||
is_subdomain(MyServer, Host)
|
||||
end, ?MYHOSTS) of
|
||||
[MyHost|_] ->
|
||||
allow_host1(MyHost, S2SHost);
|
||||
[] ->
|
||||
allow_host1(MyServer, S2SHost)
|
||||
end.
|
||||
|
||||
allow_host1(MyHost, S2SHost) ->
|
||||
case ejabberd_config:get_local_option({{s2s_host, S2SHost}, MyHost}) of
|
||||
deny -> false;
|
||||
allow -> true;
|
||||
_ ->
|
||||
case ejabberd_config:get_local_option({s2s_default_policy, MyHost}) of
|
||||
deny -> false;
|
||||
_ ->
|
||||
case ejabberd_hooks:run_fold(s2s_allow_host, MyHost,
|
||||
allow, [MyHost, S2SHost]) of
|
||||
deny -> false;
|
||||
allow -> true;
|
||||
_ -> true
|
||||
end
|
||||
end
|
||||
case ejabberd_config:get_local_option({{s2s_host, S2SHost},MyServer}) of
|
||||
deny -> false;
|
||||
allow -> true;
|
||||
_ ->
|
||||
case ejabberd_config:get_local_option({s2s_default_policy, MyServer}) of
|
||||
deny -> false;
|
||||
allow -> true;
|
||||
_ -> true %% The default s2s policy is allow
|
||||
end
|
||||
end.
|
||||
|
||||
%% Get information about S2S connections of the specified type.
|
||||
|
||||
+6
-15
@@ -5,7 +5,7 @@
|
||||
%%% Created : 6 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -177,9 +177,8 @@ init([{SockMod, Socket}, Opts]) ->
|
||||
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("to", Attrs),
|
||||
xml:get_attr_s("version", Attrs) == "1.0"} of
|
||||
{"jabber:server", _, Server, true} when
|
||||
{"jabber:server", _, true} when
|
||||
StateData#state.tls and (not StateData#state.authenticated) ->
|
||||
send_text(StateData, ?STREAM_HEADER(" version='1.0'")),
|
||||
SASL =
|
||||
@@ -213,23 +212,15 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
||||
end,
|
||||
send_element(StateData,
|
||||
{xmlelement, "stream:features", [],
|
||||
SASL ++ StartTLS ++
|
||||
ejabberd_hooks:run_fold(
|
||||
s2s_stream_features,
|
||||
Server,
|
||||
[], [Server])}),
|
||||
SASL ++ StartTLS}),
|
||||
{next_state, wait_for_feature_request, StateData};
|
||||
{"jabber:server", _, Server, true} when
|
||||
{"jabber:server", _, true} when
|
||||
StateData#state.authenticated ->
|
||||
send_text(StateData, ?STREAM_HEADER(" version='1.0'")),
|
||||
send_element(StateData,
|
||||
{xmlelement, "stream:features", [],
|
||||
ejabberd_hooks:run_fold(
|
||||
s2s_stream_features,
|
||||
Server,
|
||||
[], [Server])}),
|
||||
{xmlelement, "stream:features", [], []}),
|
||||
{next_state, stream_established, StateData};
|
||||
{"jabber:server", "jabber:server:dialback", _Server, _} ->
|
||||
{"jabber:server", "jabber:server:dialback", _} ->
|
||||
send_text(StateData, ?STREAM_HEADER("")),
|
||||
{next_state, stream_established, StateData};
|
||||
_ ->
|
||||
|
||||
+32
-50
@@ -5,7 +5,7 @@
|
||||
%%% Created : 6 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -51,7 +51,6 @@
|
||||
handle_sync_event/4,
|
||||
handle_info/3,
|
||||
terminate/3,
|
||||
print_state/1,
|
||||
code_change/4,
|
||||
test_get_addr_port/1,
|
||||
get_addr_port/1]).
|
||||
@@ -266,12 +265,10 @@ open_socket1(Host, Port) ->
|
||||
open_socket2(Type, Addr, Port) ->
|
||||
?DEBUG("s2s_out: connecting to ~p:~p~n", [Addr, Port]),
|
||||
Timeout = outgoing_s2s_timeout(),
|
||||
SockOpts = try erlang:system_info(otp_release) >= "R13B" of
|
||||
true -> [{send_timeout_close, true}];
|
||||
false -> []
|
||||
catch
|
||||
_:_ -> []
|
||||
end,
|
||||
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},
|
||||
@@ -300,12 +297,11 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
||||
{next_state, wait_for_features, StateData, ?FSMTIMEOUT};
|
||||
{"jabber:server", "", true} when StateData#state.use_v10 ->
|
||||
{next_state, wait_for_features, StateData#state{db_enabled = false}, ?FSMTIMEOUT};
|
||||
{NSProvided, DB, _} ->
|
||||
{NSProvided, _, _} ->
|
||||
send_text(StateData, ?INVALID_NAMESPACE_ERR),
|
||||
?INFO_MSG("Closing s2s connection: ~s -> ~s (invalid namespace).~n"
|
||||
"Namespace provided: ~p~nNamespace expected: \"jabber:server\"~n"
|
||||
"xmlns:db provided: ~p~nAll attributes: ~p",
|
||||
[StateData#state.myname, StateData#state.server, NSProvided, DB, Attrs]),
|
||||
"Namespace provided: ~p~nNamespace expected: \"jabber:server\"",
|
||||
[StateData#state.myname, StateData#state.server, NSProvided]),
|
||||
{stop, normal, StateData}
|
||||
end;
|
||||
|
||||
@@ -876,14 +872,6 @@ terminate(Reason, StateName, StateData) ->
|
||||
end,
|
||||
ok.
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: print_state/1
|
||||
%% Purpose: Prepare the state to be printed on error log
|
||||
%% Returns: State to print
|
||||
%%----------------------------------------------------------------------
|
||||
print_state(State) ->
|
||||
State.
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% Internal functions
|
||||
%%%----------------------------------------------------------------------
|
||||
@@ -961,36 +949,30 @@ send_db_request(StateData) ->
|
||||
Key ->
|
||||
Key
|
||||
end,
|
||||
NewStateData = StateData#state{new = New},
|
||||
try
|
||||
case New of
|
||||
false ->
|
||||
ok;
|
||||
Key1 ->
|
||||
send_element(StateData,
|
||||
{xmlelement,
|
||||
"db:result",
|
||||
[{"from", StateData#state.myname},
|
||||
{"to", Server}],
|
||||
[{xmlcdata, 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}]})
|
||||
end,
|
||||
{next_state, wait_for_validation, NewStateData, ?FSMTIMEOUT*6}
|
||||
catch
|
||||
_:_ ->
|
||||
{stop, normal, NewStateData}
|
||||
end.
|
||||
case New of
|
||||
false ->
|
||||
ok;
|
||||
Key1 ->
|
||||
send_element(StateData,
|
||||
{xmlelement,
|
||||
"db:result",
|
||||
[{"from", StateData#state.myname},
|
||||
{"to", Server}],
|
||||
[{xmlcdata, 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}]})
|
||||
end,
|
||||
{next_state, wait_for_validation, StateData#state{new = New}, ?FSMTIMEOUT*6}.
|
||||
|
||||
|
||||
is_verify_res({xmlelement, Name, Attrs, _Els}) when Name == "db:result" ->
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%%% Created : 6 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -47,8 +47,7 @@
|
||||
handle_sync_event/4,
|
||||
code_change/4,
|
||||
handle_info/3,
|
||||
terminate/3,
|
||||
print_state/1]).
|
||||
terminate/3]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("jlib.hrl").
|
||||
@@ -351,7 +350,7 @@ handle_info({route, From, To, Packet}, StateName, StateData) ->
|
||||
send_text(StateData, Text);
|
||||
deny ->
|
||||
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
|
||||
ejabberd_router:route_error(To, From, Err, Packet)
|
||||
ejabberd_router:route(To, From, Err)
|
||||
end,
|
||||
{next_state, StateName, StateData}.
|
||||
|
||||
@@ -375,14 +374,6 @@ terminate(Reason, StateName, StateData) ->
|
||||
(StateData#state.sockmod):close(StateData#state.socket),
|
||||
ok.
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: print_state/1
|
||||
%% Purpose: Prepare the state to be printed on error log
|
||||
%% Returns: State to print
|
||||
%%----------------------------------------------------------------------
|
||||
print_state(State) ->
|
||||
State.
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% Internal functions
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
+41
-40
@@ -5,7 +5,7 @@
|
||||
%%% Created : 24 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -47,7 +47,6 @@
|
||||
register_iq_handler/4,
|
||||
register_iq_handler/5,
|
||||
unregister_iq_handler/2,
|
||||
force_update_presence/1,
|
||||
connected_users/0,
|
||||
connected_users_number/0,
|
||||
user_resources/2,
|
||||
@@ -93,8 +92,7 @@ route(From, To, Packet) ->
|
||||
|
||||
open_session(SID, User, Server, Resource, Info) ->
|
||||
set_session(SID, User, Server, Resource, undefined, Info),
|
||||
mnesia:dirty_update_counter(session_counter,
|
||||
jlib:nameprep(Server), 1),
|
||||
inc_session_counter(jlib:nameprep(Server)),
|
||||
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,
|
||||
@@ -107,8 +105,7 @@ close_session(SID, User, Server, Resource) ->
|
||||
end,
|
||||
F = fun() ->
|
||||
mnesia:delete({session, SID}),
|
||||
mnesia:dirty_update_counter(session_counter,
|
||||
jlib:nameprep(Server), -1)
|
||||
dec_session_counter(jlib:nameprep(Server))
|
||||
end,
|
||||
mnesia:sync_dirty(F),
|
||||
JID = jlib:make_jid(User, Server, Resource),
|
||||
@@ -266,7 +263,6 @@ init([]) ->
|
||||
mnesia:add_table_index(session, usr),
|
||||
mnesia:add_table_index(session, us),
|
||||
mnesia:add_table_copy(session, node(), ram_copies),
|
||||
mnesia:add_table_copy(session_counter, node(), ram_copies),
|
||||
mnesia:subscribe(system),
|
||||
ets:new(sm_iqtable, [named_table]),
|
||||
lists:foreach(
|
||||
@@ -320,7 +316,7 @@ handle_info({route, From, To, Packet}, State) ->
|
||||
end,
|
||||
{noreply, State};
|
||||
handle_info({mnesia_system_event, {mnesia_down, Node}}, State) ->
|
||||
recount_session_table(Node),
|
||||
clean_table_from_bad_node(Node),
|
||||
{noreply, State};
|
||||
handle_info({register_iq_handler, Host, XMLNS, Module, Function}, State) ->
|
||||
ets:insert(sm_iqtable, {{XMLNS, Host}, Module, Function}),
|
||||
@@ -377,9 +373,7 @@ set_session(SID, User, Server, Resource, Priority, Info) ->
|
||||
end,
|
||||
mnesia:sync_dirty(F).
|
||||
|
||||
%% Recalculates alive sessions when Node goes down
|
||||
%% and updates session and session_counter tables
|
||||
recount_session_table(Node) ->
|
||||
clean_table_from_bad_node(Node) ->
|
||||
F = fun() ->
|
||||
Es = mnesia:select(
|
||||
session,
|
||||
@@ -387,22 +381,12 @@ recount_session_table(Node) ->
|
||||
[{'==', {node, '$1'}, Node}],
|
||||
['$_']}]),
|
||||
lists:foreach(fun(E) ->
|
||||
{_, LServer} = E#session.us,
|
||||
dec_session_counter(LServer),
|
||||
mnesia:delete({session, E#session.sid})
|
||||
end, Es),
|
||||
%% reset session_counter table with active sessions
|
||||
mnesia:clear_table(session_counter),
|
||||
lists:foreach(fun(Server) ->
|
||||
LServer = jlib:nameprep(Server),
|
||||
Hs = mnesia:select(session,
|
||||
[{#session{usr = '$1', _ = '_'},
|
||||
[{'==', {element, 2, '$1'}, LServer}],
|
||||
['$1']}]),
|
||||
mnesia:write(
|
||||
#session_counter{vhost = LServer,
|
||||
count = length(Hs)})
|
||||
end, ?MYHOSTS)
|
||||
end, Es)
|
||||
end,
|
||||
mnesia:async_dirty(F).
|
||||
mnesia:sync_dirty(F).
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
@@ -497,7 +481,7 @@ do_route(From, To, Packet) ->
|
||||
_ ->
|
||||
Err =
|
||||
jlib:make_error_reply(
|
||||
Packet, ?ERR_SERVICE_UNAVAILABLE),
|
||||
Packet, ?ERR_RECIPIENT_UNAVAILABLE),
|
||||
ejabberd_router:route(To, From, Err)
|
||||
end;
|
||||
_ ->
|
||||
@@ -573,10 +557,9 @@ route_message(From, To, Packet) ->
|
||||
_ ->
|
||||
case ejabberd_auth:is_user_exists(LUser, LServer) of
|
||||
true ->
|
||||
is_privacy_allow(From, To, Packet) andalso
|
||||
ejabberd_hooks:run(offline_message_hook,
|
||||
LServer,
|
||||
[From, To, Packet]);
|
||||
ejabberd_hooks:run(offline_message_hook,
|
||||
LServer,
|
||||
[From, To, Packet]);
|
||||
_ ->
|
||||
Err = jlib:make_error_reply(
|
||||
Packet, ?ERR_SERVICE_UNAVAILABLE),
|
||||
@@ -680,6 +663,34 @@ get_max_user_sessions(LUser, Host) ->
|
||||
_ -> ?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).
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
process_iq(From, To, Packet) ->
|
||||
@@ -713,16 +724,6 @@ process_iq(From, To, Packet) ->
|
||||
ok
|
||||
end.
|
||||
|
||||
force_update_presence({LUser, _LServer} = US) ->
|
||||
case catch mnesia:dirty_index_read(session, US, #session.us) of
|
||||
{'EXIT', _Reason} ->
|
||||
ok;
|
||||
Ss ->
|
||||
lists:foreach(fun(#session{sid = {_, Pid}}) ->
|
||||
Pid ! {force_update_presence, LUser}
|
||||
end, Ss)
|
||||
end.
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%% ejabberd commands
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%%% Created : 23 Aug 2006 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%%% Created : 31 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%%% Created : 21 Mar 2007 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%%% Created : 18 Jul 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
+5
-12
@@ -5,7 +5,7 @@
|
||||
%%% Created : 27 Jan 2006 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -84,7 +84,7 @@ update_info() ->
|
||||
update_info(Dir, Files) ->
|
||||
Beams = lists:sort(get_beams(Files)),
|
||||
UpdatedBeams = get_updated_beams(Beams),
|
||||
?DEBUG("beam files: ~p~n", [UpdatedBeams]),
|
||||
?INFO_MSG("beam files: ~p~n", [UpdatedBeams]),
|
||||
{Script, LowLevelScript, Check} = build_script(Dir, UpdatedBeams),
|
||||
{ok, Dir, UpdatedBeams, Script, LowLevelScript, Check}.
|
||||
|
||||
@@ -124,21 +124,14 @@ get_current_version(Module) ->
|
||||
%% @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, "..")}]),
|
||||
case Check of
|
||||
ok ->
|
||||
?DEBUG("script: ~p~n", [Script]),
|
||||
?DEBUG("low level script: ~p~n", [LowLevelScript]),
|
||||
?DEBUG("check: ~p~n", [Check]);
|
||||
_ ->
|
||||
?ERROR_MSG("script: ~p~n", [Script]),
|
||||
?ERROR_MSG("low level script: ~p~n", [LowLevelScript]),
|
||||
?ERROR_MSG("check: ~p~n", [Check])
|
||||
end,
|
||||
?INFO_MSG("check: ~p~n", [Check]),
|
||||
{Script, LowLevelScript, Check}.
|
||||
|
||||
%% Copied from Erlang/OTP file: lib/sasl/src/systools.hrl
|
||||
|
||||
@@ -26,7 +26,7 @@ EFLAGS += -pz ..
|
||||
|
||||
# make debug=true to compile Erlang module with debug informations.
|
||||
ifdef debug
|
||||
EFLAGS+=+debug_info +export_all
|
||||
EFLAGS+=+debug_info
|
||||
endif
|
||||
|
||||
ERLSHLIBS = ../ejabberd_zlib_drv.so
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%%% Created : 19 Jan 2006 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
#FIREWALL_WINDOW=
|
||||
|
||||
#.
|
||||
#' ERL_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 processes is reached, people will
|
||||
@@ -62,7 +62,7 @@
|
||||
# Default: 250000
|
||||
# Maximum: 268435456
|
||||
#
|
||||
#ERL_PROCESSES=250000
|
||||
#PROCESSES=250000
|
||||
|
||||
#.
|
||||
#' ERL_MAX_ETS_TABLES: Maximum number of ETS and Mnesia tables
|
||||
|
||||
+19
-99
@@ -57,20 +57,17 @@ fi
|
||||
|
||||
# check the proper system user is used
|
||||
ID=`id -g`
|
||||
GIDS=`id -G`
|
||||
EJID=`id -g $INSTALLUSER`
|
||||
EXEC_CMD="false"
|
||||
for GID in $GIDS; do
|
||||
if [ $GID -eq 0 ] ; then
|
||||
EXEC_CMD="su ${INSTALLUSER} -p -c"
|
||||
fi
|
||||
done
|
||||
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 4
|
||||
exit 1
|
||||
fi
|
||||
|
||||
NAME=-name
|
||||
@@ -94,7 +91,7 @@ fi
|
||||
if [ "$EJABBERD_PRIV_PATH" = "" ]; then
|
||||
EJABBERD_PRIV_PATH=$EJABBERDDIR/priv
|
||||
fi
|
||||
if [ "$EJABBERD_BIN_PATH" = "" ]; then
|
||||
if [ "$EJABBRD_BIN_PATH" = "" ]; then
|
||||
EJABBERD_BIN_PATH=$EJABBERD_PRIV_PATH/bin
|
||||
fi
|
||||
if [ "$EJABBERD_SO_PATH" = "" ]; then
|
||||
@@ -153,7 +150,7 @@ debug ()
|
||||
echo ""
|
||||
echo "IMPORTANT: we will attempt to attach an INTERACTIVE shell"
|
||||
echo "to an already running ejabberd node."
|
||||
echo "If an ERROR is printed, it means the connection was not successful."
|
||||
echo "If an ERROR is printed, it means the connection was not succesfull."
|
||||
echo "You can interact with the ejabberd node if you know how to use it."
|
||||
echo "Please be extremely cautious with your actions,"
|
||||
echo "and exit immediately if you are not completely sure."
|
||||
@@ -162,16 +159,11 @@ debug ()
|
||||
echo " control+c, control+c"
|
||||
echo ""
|
||||
echo "--------------------------------------------------------------------"
|
||||
echo "To bypass permanently this warning, add to ejabberdctl.cfg the line:"
|
||||
echo " EJABBERD_BYPASS_WARNINGS=true"
|
||||
echo "Press any key to continue"
|
||||
if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then
|
||||
read foo
|
||||
fi
|
||||
read foo
|
||||
echo ""
|
||||
TTY=`tty | sed -e 's/.*\///g'`
|
||||
$EXEC_CMD "$ERL \
|
||||
$NAME debug-${TTY}-${ERLANG_NODE} \
|
||||
$NAME debug-${ERLANG_NODE} \
|
||||
-remsh $ERLANG_NODE \
|
||||
-hidden \
|
||||
$ERLANG_OPTS $ARGS \"$@\""
|
||||
@@ -192,12 +184,8 @@ live ()
|
||||
echo " q(). and press the Enter key"
|
||||
echo ""
|
||||
echo "--------------------------------------------------------------------"
|
||||
echo "To bypass permanently this warning, add to ejabberdctl.cfg the line:"
|
||||
echo " EJABBERD_BYPASS_WARNINGS=true"
|
||||
echo "Press any key to continue"
|
||||
if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then
|
||||
read foo
|
||||
fi
|
||||
read foo
|
||||
echo ""
|
||||
$EXEC_CMD "$ERL \
|
||||
$NAME $ERLANG_NODE \
|
||||
@@ -229,88 +217,20 @@ help ()
|
||||
ctl ()
|
||||
{
|
||||
COMMAND=$@
|
||||
|
||||
# Control number of connections identifiers
|
||||
# using flock if available. Expects a linux-style
|
||||
# flock that can lock a file descriptor.
|
||||
MAXCONNID=100
|
||||
CONNLOCKDIR=@LOCALSTATEDIR@/lock/ejabberdctl
|
||||
FLOCK='/usr/bin/flock'
|
||||
if [ ! -x "$FLOCK" ] ; then
|
||||
JOT='/usr/bin/jot'
|
||||
if [ ! -x "$JOT" ] ; then
|
||||
# no flock or jot, simply invoke ctlexec()
|
||||
CTL_CONN="ctl-${ERLANG_NODE}"
|
||||
ctlexec $CTL_CONN $COMMAND
|
||||
result=$?
|
||||
else
|
||||
# no flock, but at least there is jot
|
||||
RAND=`jot -r 1 0 $MAXCONNID`
|
||||
CTL_CONN="ctl-${RAND}-${ERLANG_NODE}"
|
||||
ctlexec $CTL_CONN $COMMAND
|
||||
result=$?
|
||||
fi
|
||||
else
|
||||
# we have flock so we get a lock
|
||||
# on one of a limited number of
|
||||
# conn names -- this allows
|
||||
# concurrent invocations using a bound
|
||||
# number of atoms
|
||||
for N in $(seq 1 $MAXCONNID); do
|
||||
CTL_CONN="ejabberdctl-$N"
|
||||
CTL_LOCKFILE="$CONNLOCKDIR/$CTL_CONN"
|
||||
(
|
||||
exec 8>"$CTL_LOCKFILE"
|
||||
if flock --nb 8; then
|
||||
ctlexec $CTL_CONN $COMMAND
|
||||
ssresult=$?
|
||||
# segregate from possible flock exit(1)
|
||||
ssresult=$(expr $ssresult \* 10)
|
||||
exit $ssresult
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
)
|
||||
result=$?
|
||||
if [ $result -eq 1 ]; then
|
||||
# means we errored out in flock
|
||||
# rather than in the exec - stay in the loop
|
||||
# trying other conn names...
|
||||
badlock=1
|
||||
else
|
||||
badlock=""
|
||||
break;
|
||||
fi
|
||||
done
|
||||
result=$(expr $result / 10)
|
||||
fi
|
||||
|
||||
if [ "$badlock" ];then
|
||||
echo "Ran out of connections to try. Your ejabberd processes" >&2
|
||||
echo "may be stuck or this is a very busy server. For very" >&2
|
||||
echo "busy servers, consider raising MAXCONNID in ejabberdctl">&2
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
case $result in
|
||||
0) :;;
|
||||
1) :;;
|
||||
2) help;;
|
||||
3) help;;
|
||||
esac
|
||||
return $result
|
||||
}
|
||||
|
||||
ctlexec ()
|
||||
{
|
||||
CONN_NAME=$1; shift
|
||||
COMMAND=$@
|
||||
$EXEC_CMD "$ERL \
|
||||
$NAME ${CONN_NAME} \
|
||||
$NAME ctl-${ERLANG_NODE} \
|
||||
-noinput \
|
||||
-hidden \
|
||||
-pa $EJABBERD_EBIN_PATH \
|
||||
-s ejabberd_ctl -extra $ERLANG_NODE $COMMAND"
|
||||
result=$?
|
||||
case $result in
|
||||
0) :;;
|
||||
1) :;;
|
||||
2) help;;
|
||||
3) help;;
|
||||
esac
|
||||
return $result
|
||||
}
|
||||
|
||||
# display ctl usage
|
||||
@@ -335,7 +255,7 @@ wait_for_status()
|
||||
status=4
|
||||
while [ $status -ne $1 ]; do
|
||||
sleep $3
|
||||
timeout=$(($timeout - 1))
|
||||
let timeout=timeout-1
|
||||
[ $timeout -eq 0 ] && {
|
||||
status=$1
|
||||
} || {
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
%%% Created : 22 Aug 2005 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
@@ -286,16 +286,6 @@ ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
|
||||
responseName [10] LDAPOID OPTIONAL,
|
||||
response [11] OCTET STRING OPTIONAL }
|
||||
|
||||
passwdModifyOID LDAPOID ::= "1.3.6.1.4.1.4203.1.11.1"
|
||||
|
||||
PasswdModifyRequestValue ::= SEQUENCE {
|
||||
userIdentity [0] OCTET STRING OPTIONAL,
|
||||
oldPasswd [1] OCTET STRING OPTIONAL,
|
||||
newPasswd [2] OCTET STRING OPTIONAL }
|
||||
|
||||
PasswdModifyResponseValue ::= SEQUENCE {
|
||||
genPasswd [0] OCTET STRING OPTIONAL }
|
||||
|
||||
END
|
||||
|
||||
|
||||
|
||||
+5
-12
@@ -1,4 +1,4 @@
|
||||
# $Id: Makefile.in 2842 2009-12-29 19:10:52Z badlop $
|
||||
# $Id$
|
||||
|
||||
CC = @CC@
|
||||
CFLAGS = @CFLAGS@
|
||||
@@ -16,27 +16,22 @@ EFLAGS += -pz ..
|
||||
|
||||
# make debug=true to compile Erlang module with debug informations.
|
||||
ifdef debug
|
||||
EFLAGS+=+debug_info +export_all
|
||||
EFLAGS+=+debug_info
|
||||
endif
|
||||
|
||||
OUTDIR = ..
|
||||
SOURCES = $(wildcard *.erl) ELDAPv3.erl eldap_filter_yecc.erl
|
||||
SOURCES = $(wildcard *.erl) ELDAPv3.erl
|
||||
BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam))
|
||||
|
||||
|
||||
all: $(BEAMS) ELDAPv3.beam eldap_filter_yecc.beam
|
||||
all: $(BEAMS) ELDAPv3.beam
|
||||
|
||||
ELDAPv3.beam: ELDAPv3.erl
|
||||
|
||||
ELDAPv3.erl: ELDAPv3.asn
|
||||
@ERLC@ $(ASN_FLAGS) -W $(EFLAGS) $<
|
||||
|
||||
eldap_filter_yecc.beam: eldap_filter_yecc.erl
|
||||
|
||||
eldap_filter_yecc.erl: eldap_filter_yecc.yrl
|
||||
@ERLC@ -W $<
|
||||
|
||||
$(OUTDIR)/%.beam: %.erl ELDAPv3.erl eldap_filter_yecc.erl
|
||||
$(OUTDIR)/%.beam: %.erl ELDAPv3.erl
|
||||
@ERLC@ -W $(EFLAGS) -o $(OUTDIR) $<
|
||||
|
||||
clean:
|
||||
@@ -44,8 +39,6 @@ clean:
|
||||
rm -f ELDAPv3.erl
|
||||
rm -f ELDAPv3.hrl
|
||||
rm -f ELDAPv3.beam
|
||||
rm -f eldap_filter_yecc.erl
|
||||
rm -f eldap_filter_yecc.beam
|
||||
rm -f $(BEAMS)
|
||||
|
||||
distclean: clean
|
||||
|
||||
@@ -4,7 +4,7 @@ include ..\Makefile.inc
|
||||
EFLAGS = -I .. -pz ..
|
||||
|
||||
OUTDIR = ..
|
||||
BEAMS = ..\eldap.beam ..\eldap_filter.beam ..\eldap_pool.beam ..\eldap_utils.beam ..\eldap_filter_yecc.beam
|
||||
BEAMS = ..\eldap.beam ..\eldap_filter.beam ..\eldap_pool.beam ..\eldap_utils.beam
|
||||
|
||||
ASN_FLAGS = -bber_bin +optimize +driver
|
||||
|
||||
@@ -15,16 +15,11 @@ Clean :
|
||||
-@erase ELDAPv3.erl
|
||||
-@erase ELDAPv3.hrl
|
||||
-@erase ELDAPv3.beam
|
||||
-@erase eldap_filter_yecc.erl
|
||||
-@erase eldap_filter_yecc.beam
|
||||
-@erase $(BEAMS)
|
||||
|
||||
ELDAPv3.erl : ELDAPv3.asn
|
||||
erlc $(ASN_FLAGS) -W $(EFLAGS) ELDAPv3.asn
|
||||
|
||||
eldap_filter_yecc.erl: eldap_filter_yecc.yrl
|
||||
erlc -W eldap_filter_yecc.yrl
|
||||
|
||||
$(OUTDIR)\eldap.beam : eldap.erl ELDAPv3.erl
|
||||
erlc -W $(EFLAGS) -o $(OUTDIR) eldap.erl
|
||||
|
||||
@@ -39,6 +34,3 @@ $(OUTDIR)\eldap_utils.beam : eldap_utils.erl
|
||||
|
||||
$(OUTDIR)\eldap_pool.beam : eldap_pool.erl
|
||||
erlc -W $(EFLAGS) -o $(OUTDIR) eldap_pool.erl
|
||||
|
||||
$(OUTDIR)\eldap_filter_yecc.beam : eldap_filter_yecc.erl
|
||||
erlc -W $(EFLAGS) -o $(OUTDIR) eldap_filter_yecc.erl
|
||||
|
||||
+24
-91
@@ -33,11 +33,8 @@
|
||||
|
||||
%%% Modified by Alexey Shchepin <alexey@sevcom.net>
|
||||
|
||||
%%% Modified by Evgeniy Khramtsov <ekhramtsov@process-one.net>
|
||||
%%% Modified by Evgeniy Khramtsov <xram@jabber.ru>
|
||||
%%% Implemented queue for bind() requests to prevent pending binds.
|
||||
%%% Implemented extensibleMatch/2 function.
|
||||
%%% Implemented LDAP Extended Operations (currently only Password Modify
|
||||
%%% is supported - RFC 3062).
|
||||
|
||||
%%% Modified by Christophe Romain <christophe.romain@process-one.net>
|
||||
%%% Improve error case handling
|
||||
@@ -74,9 +71,9 @@
|
||||
|
||||
-export([baseObject/0,singleLevel/0,wholeSubtree/0,close/1,
|
||||
equalityMatch/2,greaterOrEqual/2,lessOrEqual/2,
|
||||
approxMatch/2,search/2,substrings/2,present/1,extensibleMatch/2,
|
||||
approxMatch/2,search/2,substrings/2,present/1,
|
||||
'and'/1,'or'/1,'not'/1,modify/3, mod_add/2, mod_delete/2,
|
||||
mod_replace/2, add/3, delete/2, modify_dn/5, modify_passwd/3, bind/3]).
|
||||
mod_replace/2, add/3, delete/2, modify_dn/5, bind/3]).
|
||||
-export([get_status/1]).
|
||||
|
||||
%% gen_fsm callbacks
|
||||
@@ -130,10 +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, Opts) ->
|
||||
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, Opts}, []).
|
||||
gen_fsm:start_link({local, Reg_name}, ?MODULE, {Hosts, Port, Rootdn, Passwd, Encrypt}, []).
|
||||
|
||||
%%% --------------------------------------------------------------------
|
||||
%%% Get status of connection.
|
||||
@@ -243,10 +239,6 @@ modify_dn(Handle, Entry, NewRDN, DelOldRDN, NewSup)
|
||||
{modify_dn, Entry, NewRDN, bool_p(DelOldRDN), optional(NewSup)},
|
||||
?CALL_TIMEOUT).
|
||||
|
||||
modify_passwd(Handle, DN, Passwd) when is_list(DN), is_list(Passwd) ->
|
||||
Handle1 = get_handle(Handle),
|
||||
gen_fsm:sync_send_event(
|
||||
Handle1, {modify_passwd, DN, Passwd}, ?CALL_TIMEOUT).
|
||||
|
||||
%%% --------------------------------------------------------------------
|
||||
%%% Bind.
|
||||
@@ -382,29 +374,6 @@ substrings(Type, SubStr) when is_list(Type), is_list(SubStr) ->
|
||||
{substrings,#'SubstringFilter'{type = Type,
|
||||
substrings = Ss}}.
|
||||
|
||||
%%%
|
||||
%%% extensibleMatch filter.
|
||||
%%% FIXME: Describe the purpose of this filter.
|
||||
%%%
|
||||
%%% Value ::= string( <attribute> )
|
||||
%%% Opts ::= listof( {matchingRule, Str} | {type, Str} | {dnAttributes, true} )
|
||||
%%%
|
||||
%%% Example: extensibleMatch("Fred", [{matchingRule, "1.2.3.4.5"}, {type, "cn"}]).
|
||||
%%%
|
||||
extensibleMatch(Value, Opts) when is_list(Value), is_list(Opts) ->
|
||||
MRA = #'MatchingRuleAssertion'{matchValue=Value},
|
||||
{extensibleMatch, extensibleMatch_opts(Opts, MRA)}.
|
||||
|
||||
extensibleMatch_opts([{matchingRule, Rule} | Opts], MRA) when is_list(Rule) ->
|
||||
extensibleMatch_opts(Opts, MRA#'MatchingRuleAssertion'{matchingRule=Rule});
|
||||
extensibleMatch_opts([{type, Desc} | Opts], MRA) when is_list(Desc) ->
|
||||
extensibleMatch_opts(Opts, MRA#'MatchingRuleAssertion'{type=Desc});
|
||||
extensibleMatch_opts([{dnAttributes, true} | Opts], MRA) ->
|
||||
extensibleMatch_opts(Opts, MRA#'MatchingRuleAssertion'{dnAttributes=true});
|
||||
extensibleMatch_opts([_ | Opts], MRA) ->
|
||||
extensibleMatch_opts(Opts, MRA);
|
||||
extensibleMatch_opts([], MRA) ->
|
||||
MRA.
|
||||
|
||||
get_handle(Pid) when is_pid(Pid) -> Pid;
|
||||
get_handle(Atom) when is_atom(Atom) -> Atom;
|
||||
@@ -424,18 +393,15 @@ get_handle(Name) when is_list(Name) -> list_to_atom("eldap_" ++ Name).
|
||||
%%----------------------------------------------------------------------
|
||||
init([]) ->
|
||||
case get_config() of
|
||||
{ok, Hosts, Rootdn, Passwd, Opts} ->
|
||||
init({Hosts, Rootdn, Passwd, Opts});
|
||||
{ok, Hosts, Rootdn, Passwd, Encrypt} ->
|
||||
init({Hosts, Rootdn, Passwd, Encrypt});
|
||||
{error, Reason} ->
|
||||
{stop, Reason}
|
||||
end;
|
||||
init({Hosts, Port, Rootdn, Passwd, Opts}) ->
|
||||
init({Hosts, Port, Rootdn, Passwd, Encrypt}) ->
|
||||
catch ssl:start(),
|
||||
ssl:seed(randoms:get_string()),
|
||||
Encrypt = case proplists:get_value(encrypt, Opts) of
|
||||
tls -> tls;
|
||||
_ -> none
|
||||
end,
|
||||
{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
|
||||
@@ -448,14 +414,7 @@ init({Hosts, Port, Rootdn, Passwd, Opts}) ->
|
||||
end;
|
||||
PT -> PT
|
||||
end,
|
||||
TLSOpts = case proplists:get_value(tls_verify, Opts) of
|
||||
soft ->
|
||||
[{verify, 1}];
|
||||
hard ->
|
||||
[{verify, 2}];
|
||||
_ ->
|
||||
[{verify, 0}]
|
||||
end,
|
||||
TLSOpts = [verify_none],
|
||||
{ok, connecting, #eldap{hosts = Hosts,
|
||||
port = PortTemp,
|
||||
rootdn = Rootdn,
|
||||
@@ -712,16 +671,6 @@ gen_req({modify_dn, Entry, NewRDN, DelOldRDN, NewSup}) ->
|
||||
deleteoldrdn = DelOldRDN,
|
||||
newSuperior = NewSup}};
|
||||
|
||||
gen_req({modify_passwd, DN, Passwd}) ->
|
||||
{ok, ReqVal} = asn1rt:encode(
|
||||
'ELDAPv3', 'PasswdModifyRequestValue',
|
||||
#'PasswdModifyRequestValue'{
|
||||
userIdentity = DN,
|
||||
newPasswd = Passwd}),
|
||||
{extendedReq,
|
||||
#'ExtendedRequest'{requestName = ?passwdModifyOID,
|
||||
requestValue = list_to_binary(ReqVal)}};
|
||||
|
||||
gen_req({bind, RootDN, Passwd}) ->
|
||||
{bindRequest,
|
||||
#'BindRequest'{version = ?LDAP_VERSION,
|
||||
@@ -796,11 +745,6 @@ recvd_packet(Pkt, S) ->
|
||||
cancel_timer(Timer),
|
||||
Reply = check_bind_reply(Result, From),
|
||||
{reply, Reply, From, S#eldap{dict = New_dict}};
|
||||
{extendedReq, {extendedResp, Result}} ->
|
||||
New_dict = dict:erase(Id, Dict),
|
||||
cancel_timer(Timer),
|
||||
Reply = check_extended_reply(Result, From),
|
||||
{reply, Reply, From, S#eldap{dict = New_dict}};
|
||||
{OtherName, OtherResult} ->
|
||||
New_dict = dict:erase(Id, Dict),
|
||||
cancel_timer(Timer),
|
||||
@@ -825,15 +769,6 @@ check_bind_reply(#'BindResponse'{resultCode = Reason}, _From) ->
|
||||
check_bind_reply(Other, _From) ->
|
||||
{error, Other}.
|
||||
|
||||
%% TODO: process reply depending on requestName:
|
||||
%% this requires BER-decoding of #'ExtendedResponse'.response
|
||||
check_extended_reply(#'ExtendedResponse'{resultCode = success}, _From) ->
|
||||
ok;
|
||||
check_extended_reply(#'ExtendedResponse'{resultCode = Reason}, _From) ->
|
||||
{error, Reason};
|
||||
check_extended_reply(Other, _From) ->
|
||||
{error, Other}.
|
||||
|
||||
get_op_rec(Id, Dict) ->
|
||||
case dict:find(Id, Dict) of
|
||||
{ok, [{Timer, _Command, From, Name}|Res]} ->
|
||||
@@ -969,7 +904,7 @@ connect_bind(S) ->
|
||||
tls ->
|
||||
SockMod = ssl,
|
||||
SslOpts = [{packet, asn1}, {active, true}, {keepalive, true},
|
||||
binary | S#eldap.tls_options],
|
||||
binary],
|
||||
ssl:connect(Host, S#eldap.port, SslOpts);
|
||||
%% starttls -> %% TODO: Implement STARTTLS;
|
||||
_ ->
|
||||
@@ -1038,8 +973,6 @@ v_filter({lessOrEqual,AV}) -> {lessOrEqual,AV};
|
||||
v_filter({approxMatch,AV}) -> {approxMatch,AV};
|
||||
v_filter({present,A}) -> {present,A};
|
||||
v_filter({substrings,S}) when is_record(S,'SubstringFilter') -> {substrings,S};
|
||||
v_filter({extensibleMatch, S}) when is_record(S, 'MatchingRuleAssertion') ->
|
||||
{extensibleMatch, S};
|
||||
v_filter(_Filter) -> throw({error,concat(["unknown filter: ",_Filter])}).
|
||||
|
||||
v_modifications(Mods) ->
|
||||
@@ -1085,8 +1018,8 @@ get_config() ->
|
||||
case file:consult(File) of
|
||||
{ok, Entries} ->
|
||||
case catch parse(Entries) of
|
||||
{ok, Hosts, Port, Rootdn, Passwd, Opts} ->
|
||||
{ok, Hosts, Port, Rootdn, Passwd, Opts};
|
||||
{ok, Hosts, Port, Rootdn, Passwd, Encrypt} ->
|
||||
{ok, Hosts, Port, Rootdn, Passwd, Encrypt};
|
||||
{error, Reason} ->
|
||||
{error, Reason};
|
||||
{'EXIT', Reason} ->
|
||||
@@ -1102,7 +1035,7 @@ parse(Entries) ->
|
||||
get_integer(port, Entries),
|
||||
get_list(rootdn, Entries),
|
||||
get_list(passwd, Entries),
|
||||
get_list(options, Entries)}.
|
||||
get_atom(encrypt, Entries)}.
|
||||
|
||||
get_integer(Key, List) ->
|
||||
case lists:keysearch(Key, 1, List) of
|
||||
@@ -1124,15 +1057,15 @@ 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 is_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_atom(Key, List) ->
|
||||
case lists:keysearch(Key, 1, List) of
|
||||
{value, {Key, Value}} when is_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),
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
+190
-65
@@ -3,10 +3,10 @@
|
||||
%%% Purpose: Converts String Representation of
|
||||
%%% LDAP Search Filter (RFC 2254)
|
||||
%%% to eldap's representation of filter
|
||||
%%% Author: Evgeniy Khramtsov <ekhramtsov@process-one.net>
|
||||
%%% Author: Evgeniy Khramtsov <xramtsov@gmail.com>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -24,17 +24,19 @@
|
||||
%%% 02111-1307 USA
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-module(eldap_filter).
|
||||
|
||||
%% TODO: remove this when new regexp module will be used
|
||||
-compile({nowarn_deprecated_function, {regexp, sub, 3}}).
|
||||
%%%======================
|
||||
%%% Export functions
|
||||
%%%======================
|
||||
|
||||
-export([parse/1, parse/2, do_sub/2]).
|
||||
-export([parse/1,
|
||||
parse/2,
|
||||
do_sub/2
|
||||
]).
|
||||
|
||||
%%====================================================================
|
||||
%% API
|
||||
%%====================================================================
|
||||
%%%-------------------------------------------------------------------
|
||||
%%%-------------------------------------------------------------------------
|
||||
%%% Arity: parse/1
|
||||
%%% Function: parse(RFC2254_Filter) -> {ok, EldapFilter} |
|
||||
%%% {error, bad_filter}
|
||||
@@ -45,15 +47,15 @@
|
||||
%%% to eldap's representation of filter.
|
||||
%%%
|
||||
%%% Example:
|
||||
%%% > eldap_filter:parse("(&(!(uid<=100))(mail=*))").
|
||||
%%% > eldap_filter:parse("(&(!(uid<=100))(mail=*))").
|
||||
%%%
|
||||
%%% {ok,{'and',[{'not',{lessOrEqual,{'AttributeValueAssertion',"uid","100"}}},
|
||||
%%% {present,"mail"}]}}
|
||||
%%%-------------------------------------------------------------------
|
||||
parse(L) when is_list(L) ->
|
||||
parse(L, []).
|
||||
%%% {ok,{'and',[{'not',{lessOrEqual,{'AttributeValueAssertion',"uid","100"}}},
|
||||
%%% {present,"mail"}]}}
|
||||
%%%-------------------------------------------------------------------------
|
||||
parse(RFC2254_Filter) ->
|
||||
parse(RFC2254_Filter, []).
|
||||
|
||||
%%%-------------------------------------------------------------------
|
||||
%%%-------------------------------------------------------------------------
|
||||
%%% Arity: parse/2
|
||||
%%% Function: parse(RFC2254_Filter, [SubstValue |...]) ->
|
||||
%%% {ok, EldapFilter} |
|
||||
@@ -79,53 +81,135 @@ parse(L) when is_list(L) ->
|
||||
%%% {equalityMatch,{'AttributeValueAssertion',
|
||||
%%% "jid",
|
||||
%%% "xramtsov@gmail.com"}}]}}
|
||||
%%%-------------------------------------------------------------------
|
||||
parse(L, SList) when is_list(L), is_list(SList) ->
|
||||
case catch eldap_filter_yecc:parse(scan(L, SList)) of
|
||||
{error, {_, _, Msg}} ->
|
||||
{error, Msg};
|
||||
{ok, Result} ->
|
||||
{ok, Result};
|
||||
{regexp, Err} ->
|
||||
{error, Err}
|
||||
%%%--------------------------------------------------------------------------
|
||||
parse(RFC2254_Filter, ListOfSubValues) ->
|
||||
case catch convert_filter(parse_filter(RFC2254_Filter), ListOfSubValues) of
|
||||
[EldapFilter] when is_tuple(EldapFilter) ->
|
||||
{ok, EldapFilter};
|
||||
{regexp, Error} ->
|
||||
{error, Error};
|
||||
_ ->
|
||||
{error, bad_filter}
|
||||
end.
|
||||
|
||||
%%====================================================================
|
||||
%% Internal functions
|
||||
%%====================================================================
|
||||
-define(do_scan(L), scan(Rest, [], [{L, 1} | check(Buf, S) ++ Result], L, S)).
|
||||
%%%==========================
|
||||
%%% Internal functions
|
||||
%%%==========================
|
||||
|
||||
scan(L, SList) ->
|
||||
scan(L, "", [], undefined, SList).
|
||||
%%%----------------------
|
||||
%%% split/1,4
|
||||
%%%----------------------
|
||||
split(Filter) ->
|
||||
split(Filter, 0, [], []).
|
||||
|
||||
scan("=*)" ++ Rest, Buf, Result, '(', S) ->
|
||||
scan(Rest, [], [{')', 1}, {'=*', 1} | check(Buf, S) ++ Result], ')', S);
|
||||
scan(":dn" ++ Rest, Buf, Result, '(', S) -> ?do_scan(':dn');
|
||||
scan(":=" ++ Rest, Buf, Result, '(', S) -> ?do_scan(':=');
|
||||
scan(":=" ++ Rest, Buf, Result, ':dn', S) -> ?do_scan(':=');
|
||||
scan(":=" ++ Rest, Buf, Result, ':', S) -> ?do_scan(':=');
|
||||
scan("~=" ++ Rest, Buf, Result, '(', S) -> ?do_scan('~=');
|
||||
scan(">=" ++ Rest, Buf, Result, '(', S) -> ?do_scan('>=');
|
||||
scan("<=" ++ Rest, Buf, Result, '(', S) -> ?do_scan('<=');
|
||||
scan("=" ++ Rest, Buf, Result, '(', S) -> ?do_scan('=');
|
||||
scan(":" ++ Rest, Buf, Result, '(', S) -> ?do_scan(':');
|
||||
scan(":" ++ Rest, Buf, Result, ':dn', S) -> ?do_scan(':');
|
||||
scan("&" ++ Rest, Buf, Result, '(', S) when Buf=="" -> ?do_scan('&');
|
||||
scan("|" ++ Rest, Buf, Result, '(', S) when Buf=="" -> ?do_scan('|');
|
||||
scan("!" ++ Rest, Buf, Result, '(', S) when Buf=="" -> ?do_scan('!');
|
||||
scan("*" ++ Rest, Buf, Result, '*', S) -> ?do_scan('*');
|
||||
scan("*" ++ Rest, Buf, Result, '=', S) -> ?do_scan('*');
|
||||
scan("(" ++ Rest, Buf, Result, _, S) -> ?do_scan('(');
|
||||
scan(")" ++ Rest, Buf, Result, _, S) -> ?do_scan(')');
|
||||
scan([Letter | Rest], Buf, Result, PreviosAtom, S) ->
|
||||
scan(Rest, [Letter|Buf], Result, PreviosAtom, S);
|
||||
scan([], Buf, Result, _, S) ->
|
||||
lists:reverse(check(Buf, S) ++ Result).
|
||||
split([], _, _, Result) ->
|
||||
Result;
|
||||
|
||||
check([], _) ->
|
||||
[];
|
||||
check(Buf, S) ->
|
||||
[{str, 1, do_sub(lists:reverse(Buf), S)}].
|
||||
split([H|T], Num, Rest, Result) ->
|
||||
NewNum = case H of
|
||||
$( -> Num + 1;
|
||||
$) -> Num - 1;
|
||||
_ -> Num
|
||||
end,
|
||||
if
|
||||
NewNum == 0 ->
|
||||
X = Rest++[H],
|
||||
LenX = length(X),
|
||||
if
|
||||
LenX > 2 ->
|
||||
split(T, 0, [], Result ++ [lists:sublist(X, 2, LenX-2)]);
|
||||
true ->
|
||||
split(T, 0, Rest, Result)
|
||||
end;
|
||||
true ->
|
||||
split(T, NewNum, Rest++[H], Result)
|
||||
end.
|
||||
|
||||
%%%-----------------------
|
||||
%%% parse_filter/1
|
||||
%%%-----------------------
|
||||
parse_filter(Filter) ->
|
||||
case Filter of
|
||||
[$! | T] ->
|
||||
{'not', parse_filter(T)};
|
||||
[$| | T] ->
|
||||
{'or', parse_filter(T)};
|
||||
[$& | T] ->
|
||||
{'and', parse_filter(T)};
|
||||
[$( | _] ->
|
||||
parse_filter(split(Filter));
|
||||
[List | _] when is_list(List) ->
|
||||
[parse_filter(X) || X <- Filter];
|
||||
_ ->
|
||||
Filter
|
||||
end.
|
||||
|
||||
%%%--------------------
|
||||
%%% convert_filter/2
|
||||
%%%--------------------
|
||||
convert_filter({'not', [Val | _]}, Replace) ->
|
||||
eldap:'not'(convert_filter(Val, Replace));
|
||||
|
||||
convert_filter({'or', Vals}, Replace) ->
|
||||
eldap:'or'([convert_filter(X, Replace) || X <- Vals]);
|
||||
|
||||
convert_filter({'and', Vals}, Replace) ->
|
||||
eldap:'and'([convert_filter(X, Replace) || X <- Vals]);
|
||||
|
||||
convert_filter([H|_] = Filter, Replace) when is_integer(H) ->
|
||||
parse_attr(Filter, Replace);
|
||||
|
||||
convert_filter(Filter, Replace) when is_list(Filter) ->
|
||||
[convert_filter(X, Replace) || X <- Filter].
|
||||
|
||||
%%%-----------------
|
||||
%%% parse_attr/2,3
|
||||
%%%-----------------
|
||||
parse_attr(Attr, ListOfSubValues) ->
|
||||
{Action, [_|_] = Name, [_|_] = Value} = split_attribute(Attr),
|
||||
parse_attr(Action, {Name, Value}, ListOfSubValues).
|
||||
|
||||
parse_attr(approx, {Name, Value}, ListOfSubValues) ->
|
||||
NewValue = do_sub(Value, ListOfSubValues),
|
||||
eldap:approxMatch(Name, NewValue);
|
||||
|
||||
parse_attr(greater, {Name, Value}, ListOfSubValues) ->
|
||||
NewValue = do_sub(Value, ListOfSubValues),
|
||||
eldap:greaterOrEqual(Name, NewValue);
|
||||
|
||||
parse_attr(less, {Name, Value}, ListOfSubValues) ->
|
||||
NewValue = do_sub(Value, ListOfSubValues),
|
||||
eldap:lessOrEqual(Name, NewValue);
|
||||
|
||||
parse_attr(equal, {Name, Value}, ListOfSubValues) ->
|
||||
{ok, RegSList} = regexp:split(remove_extra_asterisks(Value), "[*]"),
|
||||
Pattern = case [do_sub(X, ListOfSubValues) || X <- RegSList] of
|
||||
[Head | Tail] when Tail /= [] ->
|
||||
{Head, lists:sublist(Tail, length(Tail)-1), lists:last(Tail)};
|
||||
R ->
|
||||
R
|
||||
end,
|
||||
case Pattern of
|
||||
[V] ->
|
||||
eldap:equalityMatch(Name, V);
|
||||
{[], [], []} ->
|
||||
eldap:present(Name);
|
||||
{"", Any, ""} ->
|
||||
eldap:substrings(Name, [{any, X} || X<-Any]);
|
||||
{H, Any, ""} ->
|
||||
eldap:substrings(Name, [{initial, H}]++[{any, X} || X<-Any]);
|
||||
{"", Any, T} ->
|
||||
eldap:substrings(Name, [{any, X} || X<-Any]++[{final, T}]);
|
||||
{H, Any, T} ->
|
||||
eldap:substrings(Name, [{initial, H}]++[{any, X} || X<-Any]++[{final, T}])
|
||||
end;
|
||||
|
||||
parse_attr(_, _, _) ->
|
||||
false.
|
||||
|
||||
%%%--------------------
|
||||
%%% do_sub/2,3
|
||||
%%%--------------------
|
||||
|
||||
-define(MAX_RECURSION, 100).
|
||||
|
||||
@@ -150,9 +234,9 @@ do_sub(S, {RegExp, New}, Iter) ->
|
||||
{ok, NewS, _} when Iter =< ?MAX_RECURSION ->
|
||||
do_sub(NewS, {RegExp, New}, Iter+1);
|
||||
{ok, _, _} when Iter > ?MAX_RECURSION ->
|
||||
erlang:error(max_substitute_recursion);
|
||||
throw({regexp, max_substitute_recursion});
|
||||
_ ->
|
||||
erlang:error(bad_regexp)
|
||||
throw({regexp, bad_regexp})
|
||||
end;
|
||||
|
||||
do_sub(S, {_, _, N}, _) when N<1 ->
|
||||
@@ -167,11 +251,52 @@ do_sub(S, {RegExp, New, Times}, Iter) ->
|
||||
{ok, NewS, _} ->
|
||||
NewS;
|
||||
_ ->
|
||||
erlang:error(bad_regexp)
|
||||
throw({regexp, bad_regexp})
|
||||
end.
|
||||
|
||||
remove_extra_asterisks(String) ->
|
||||
{Res, _} = lists:foldl(
|
||||
fun(X, {Acc, Last}) ->
|
||||
case X of
|
||||
$* when Last==$* ->
|
||||
{Acc, X};
|
||||
_ ->
|
||||
{Acc ++ [X], X}
|
||||
end
|
||||
end,
|
||||
{"", ""}, String),
|
||||
Res.
|
||||
|
||||
replace_amps(String) ->
|
||||
lists:map(
|
||||
fun($&) -> "\\&";
|
||||
(Chr) -> Chr
|
||||
end, String).
|
||||
lists:foldl(
|
||||
fun(X, Acc) ->
|
||||
if
|
||||
X == $& ->
|
||||
Acc ++ "\\&";
|
||||
true ->
|
||||
Acc ++ [X]
|
||||
end
|
||||
end,
|
||||
"", String).
|
||||
|
||||
split_attribute(String) ->
|
||||
split_attribute(String, "", $0).
|
||||
|
||||
split_attribute([], _, _) ->
|
||||
{error, "", ""};
|
||||
|
||||
split_attribute([H|Tail], Acc, Last) ->
|
||||
case H of
|
||||
$= when Last==$> ->
|
||||
{greater, lists:sublist(Acc, 1, length(Acc)-1), Tail};
|
||||
$= when Last==$< ->
|
||||
{less, lists:sublist(Acc, 1, length(Acc)-1), Tail};
|
||||
$= when Last==$~ ->
|
||||
{approx, lists:sublist(Acc, 1, length(Acc)-1), Tail};
|
||||
$= when Last==$: ->
|
||||
{equal, lists:sublist(Acc, 1, length(Acc)-1), Tail};
|
||||
$= ->
|
||||
{equal, Acc, Tail};
|
||||
_ ->
|
||||
split_attribute(Tail, Acc++[H], H)
|
||||
end.
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
Nonterminals
|
||||
filter filtercomp filterlist item
|
||||
simple present substring extensible
|
||||
initial any final matchingrule xattr
|
||||
attr value.
|
||||
|
||||
Terminals str
|
||||
'(' ')' '&' '|' '!' '=' '~=' '>=' '<=' '=*' '*' ':dn' ':' ':='.
|
||||
|
||||
Rootsymbol filter.
|
||||
|
||||
filter -> '(' filtercomp ')': '$2'.
|
||||
filtercomp -> '&' filterlist: 'and'('$2').
|
||||
filtercomp -> '|' filterlist: 'or'('$2').
|
||||
filtercomp -> '!' filter: 'not'('$2').
|
||||
filtercomp -> item: '$1'.
|
||||
filterlist -> filter: '$1'.
|
||||
filterlist -> filter filterlist: flatten(['$1', '$2']).
|
||||
|
||||
item -> simple: '$1'.
|
||||
item -> present: '$1'.
|
||||
item -> substring: '$1'.
|
||||
item -> extensible: '$1'.
|
||||
|
||||
simple -> attr '=' value: equal('$1', '$3').
|
||||
simple -> attr '~=' value: approx('$1', '$3').
|
||||
simple -> attr '>=' value: greater('$1', '$3').
|
||||
simple -> attr '<=' value: less('$1', '$3').
|
||||
|
||||
present -> attr '=*': present('$1').
|
||||
|
||||
substring -> attr '=' initial '*' any: substrings('$1', ['$3', '$5']).
|
||||
substring -> attr '=' '*' any final: substrings('$1', ['$4', '$5']).
|
||||
substring -> attr '=' initial '*' any final: substrings('$1', ['$3', '$5', '$6']).
|
||||
substring -> attr '=' '*' any: substrings('$1', ['$4']).
|
||||
any -> any value '*': 'any'('$1', '$2').
|
||||
any -> '$empty': [].
|
||||
initial -> value: initial('$1').
|
||||
final -> value: final('$1').
|
||||
|
||||
extensible -> xattr ':dn' ':' matchingrule ':=' value: extensible('$6', ['$1', '$4']).
|
||||
extensible -> xattr ':' matchingrule ':=' value: extensible('$5', ['$1', '$3']).
|
||||
extensible -> xattr ':dn' ':=' value: extensible('$4', ['$1']).
|
||||
extensible -> xattr ':=' value: extensible('$3', ['$1']).
|
||||
extensible -> ':dn' ':' matchingrule ':=' value: extensible('$5', ['$3']).
|
||||
extensible -> ':' matchingrule ':=' value: extensible('$4', ['$2']).
|
||||
xattr -> value: xattr('$1').
|
||||
matchingrule -> value: matchingrule('$1').
|
||||
|
||||
attr -> str: value_of('$1').
|
||||
value -> str: value_of('$1').
|
||||
|
||||
Erlang code.
|
||||
|
||||
'and'(Value) -> eldap:'and'(Value).
|
||||
'or'(Value) -> eldap:'or'(Value).
|
||||
'not'(Value) -> eldap:'not'(Value).
|
||||
equal(Desc, Value) -> eldap:equalityMatch(Desc, Value).
|
||||
approx(Desc, Value) -> eldap:approxMatch(Desc, Value).
|
||||
greater(Desc, Value) -> eldap:greaterOrEqual(Desc, Value).
|
||||
less(Desc, Value) -> eldap:lessOrEqual(Desc, Value).
|
||||
present(Value) -> eldap:present(Value).
|
||||
extensible(Value, Opts) -> eldap:extensibleMatch(Value, Opts).
|
||||
substrings(Desc, ValueList) -> eldap:substrings(Desc, flatten(ValueList)).
|
||||
initial(Value) -> {initial, Value}.
|
||||
final(Value) -> {final, Value}.
|
||||
'any'(Token, Value) -> [Token, {any, Value}].
|
||||
xattr(Value) -> {type, Value}.
|
||||
matchingrule(Value) -> {matchingRule, Value}.
|
||||
value_of(Token) -> element(3, Token).
|
||||
flatten(List) -> lists:flatten(List).
|
||||
+12
-18
@@ -5,7 +5,7 @@
|
||||
%%% Created : 12 Nov 2006 by Evgeniy Khramtsov <xram@jabber.ru>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -31,8 +31,7 @@
|
||||
-export([
|
||||
start_link/7,
|
||||
bind/3,
|
||||
search/2,
|
||||
modify_passwd/3
|
||||
search/2
|
||||
]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
@@ -46,23 +45,18 @@ bind(PoolName, DN, Passwd) ->
|
||||
search(PoolName, Opts) ->
|
||||
do_request(PoolName, {search, [Opts]}).
|
||||
|
||||
modify_passwd(PoolName, DN, Passwd) ->
|
||||
do_request(PoolName, {modify_passwd, [DN, Passwd]}).
|
||||
|
||||
start_link(Name, Hosts, Backups, Port, Rootdn, Passwd, Opts) ->
|
||||
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, Opts) of
|
||||
{ok, Pid} ->
|
||||
pg2:join(PoolName, Pid);
|
||||
_ ->
|
||||
error
|
||||
end
|
||||
end, Hosts).
|
||||
lists:foreach(fun(Host) ->
|
||||
ID = erlang:ref_to_list(make_ref()),
|
||||
case catch eldap:start_link(ID, [Host|Backups], Port, Rootdn, Passwd, Encrypt) of
|
||||
{ok, Pid} ->
|
||||
pg2:join(PoolName, Pid);
|
||||
_ ->
|
||||
error
|
||||
end
|
||||
end, Hosts).
|
||||
|
||||
%%====================================================================
|
||||
%% Internal functions
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%%% Created : 12 Oct 2006 by Mickael Remond <mremond@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -53,17 +53,15 @@ subfilter({UIDAttr}) ->
|
||||
|
||||
%% Not tail-recursive, but it is not very terribly.
|
||||
%% It stops finding on the first not empty value.
|
||||
find_ldap_attrs([{Attr} | Rest], Attributes) ->
|
||||
find_ldap_attrs([{Attr, "%u"} | Rest], Attributes);
|
||||
find_ldap_attrs([{Attr, Format} | Rest], Attributes) ->
|
||||
case get_ldap_attr(Attr, Attributes) of
|
||||
case get_ldap_attr(Attr, Attributes) of
|
||||
Value when is_list(Value), Value /= "" ->
|
||||
{Value, Format};
|
||||
{Value, Format};
|
||||
_ ->
|
||||
find_ldap_attrs(Rest, Attributes)
|
||||
end;
|
||||
find_ldap_attrs(Rest, Attributes)
|
||||
end;
|
||||
find_ldap_attrs([], _) ->
|
||||
"".
|
||||
"".
|
||||
|
||||
get_ldap_attr(LDAPAttr, Attributes) ->
|
||||
Res = lists:filter(
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
+3
-22
@@ -5,7 +5,7 @@
|
||||
%%% Created : 30 Jul 2004 by Leif Johansson <leifj@it.su.se>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -27,15 +27,8 @@
|
||||
-module(extauth).
|
||||
-author('leifj@it.su.se').
|
||||
|
||||
-export([start/2,
|
||||
stop/1,
|
||||
init/2,
|
||||
check_password/3,
|
||||
set_password/3,
|
||||
try_register/3,
|
||||
remove_user/2,
|
||||
remove_user/3,
|
||||
is_user_exists/2]).
|
||||
-export([start/2, stop/1, init/2,
|
||||
check_password/3, set_password/3, is_user_exists/2]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
|
||||
@@ -63,18 +56,6 @@ is_user_exists(User, Server) ->
|
||||
set_password(User, Server, Password) ->
|
||||
call_port(Server, ["setpass", User, Server, Password]).
|
||||
|
||||
try_register(User, Server, Password) ->
|
||||
case call_port(Server, ["tryregister", User, Server, Password]) of
|
||||
true -> {atomic, ok};
|
||||
false -> {error, not_allowed}
|
||||
end.
|
||||
|
||||
remove_user(User, Server) ->
|
||||
call_port(Server, ["removeuser", User, Server]).
|
||||
|
||||
remove_user(User, Server, Password) ->
|
||||
call_port(Server, ["removeuser3", User, Server, Password]).
|
||||
|
||||
call_port(Server, Msg) ->
|
||||
LServer = jlib:nameprep(Server),
|
||||
gen_mod:get_module_proc(LServer, eauth) ! {call, self(), Msg},
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%%% Created : 22 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
%%% Created : 24 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
%%% Created : 10 Apr 2004 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
%%% Created : 2 Feb 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
+10
-12
@@ -5,7 +5,7 @@
|
||||
%%% Created : 23 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -382,7 +382,7 @@ iq_info_internal({xmlelement, Name, Attrs, Els}, Filter) when Name == "iq" ->
|
||||
"result" -> {result, reply};
|
||||
"error" -> {error, reply};
|
||||
_ -> {invalid, invalid}
|
||||
end,
|
||||
end,
|
||||
if
|
||||
Type1 == invalid ->
|
||||
invalid;
|
||||
@@ -404,24 +404,22 @@ iq_info_internal({xmlelement, Name, Attrs, Els}, Filter) when Name == "iq" ->
|
||||
<- FilteredEls,
|
||||
SubName /= "error"],
|
||||
{case NonErrorEls of
|
||||
[NonErrorEl] ->
|
||||
xml:get_tag_attr_s("xmlns", NonErrorEl);
|
||||
_ ->
|
||||
""
|
||||
[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,
|
||||
#iq{id = ID,
|
||||
type = Type1,
|
||||
xmlns = XMLNS,
|
||||
lang = Lang,
|
||||
sub_el = SubEl}
|
||||
end;
|
||||
end;
|
||||
Class == reply, Filter /= any ->
|
||||
reply
|
||||
end;
|
||||
|
||||
+1
-6
@@ -1,6 +1,6 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -22,7 +22,6 @@
|
||||
-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_VCARD_UPDATE, "vcard-temp:x:update").
|
||||
-define(NS_AUTH, "jabber:iq:auth").
|
||||
-define(NS_AUTH_ERROR, "jabber:iq:auth:error").
|
||||
-define(NS_REGISTER, "jabber:iq:register").
|
||||
@@ -48,7 +47,6 @@
|
||||
-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_MUC_UNIQUE, "http://jabber.org/protocol/muc#unique").
|
||||
-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").
|
||||
@@ -85,7 +83,6 @@
|
||||
|
||||
-define(NS_CAPS, "http://jabber.org/protocol/caps").
|
||||
-define(NS_SHIM, "http://jabber.org/protocol/shim").
|
||||
-define(NS_ADDRESS, "http://jabber.org/protocol/address").
|
||||
|
||||
%% CAPTCHA related NSes.
|
||||
-define(NS_OOB, "jabber:x:oob").
|
||||
@@ -141,8 +138,6 @@
|
||||
?STANZA_ERROR("407", "auth", "subscription-required")).
|
||||
-define(ERR_UNEXPECTED_REQUEST,
|
||||
?STANZA_ERROR("400", "wait", "unexpected-request")).
|
||||
-define(ERR_UNEXPECTED_REQUEST_CANCEL,
|
||||
?STANZA_ERROR("401", "cancel", "unexpected-request")).
|
||||
%-define(ERR_,
|
||||
% ?STANZA_ERROR("", "", "")).
|
||||
|
||||
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% File : mod_adhoc.erl
|
||||
%%% Author : Magnus Henoch <henoch@dtek.chalmers.se>
|
||||
%%% Purpose : Handle incoming ad-doc requests (XEP-0050)
|
||||
%%% Purpose : Handle incoming ad-doc requests (JEP-0050)
|
||||
%%% Created : 15 Nov 2005 by Magnus Henoch <henoch@dtek.chalmers.se>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
+1
-23
@@ -5,7 +5,7 @@
|
||||
%%% Created : 11 Aug 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -40,7 +40,6 @@
|
||||
disco_identity/5,
|
||||
disco_features/5,
|
||||
disco_items/5,
|
||||
send_announcement_to_all/3,
|
||||
announce_commands/4,
|
||||
announce_items/4]).
|
||||
|
||||
@@ -847,27 +846,6 @@ get_stored_motd(LServer) ->
|
||||
{"", ""}
|
||||
end.
|
||||
|
||||
%% This function is similar to others, but doesn't perform any ACL verification
|
||||
send_announcement_to_all(Host, SubjectS, BodyS) ->
|
||||
SubjectEls = if SubjectS /= [] ->
|
||||
[{xmlelement, "subject", [], [{xmlcdata, SubjectS}]}];
|
||||
true ->
|
||||
[]
|
||||
end,
|
||||
BodyEls = if BodyS /= [] ->
|
||||
[{xmlelement, "body", [], [{xmlcdata, BodyS}]}];
|
||||
true ->
|
||||
[]
|
||||
end,
|
||||
Packet = {xmlelement, "message", [{"type", "normal"}], SubjectEls ++ BodyEls},
|
||||
Sessions = ejabberd_sm:dirty_get_sessions_list(),
|
||||
Local = jlib:make_jid("", Host, ""),
|
||||
lists:foreach(
|
||||
fun({U, S, R}) ->
|
||||
Dest = jlib:make_jid(U, S, R),
|
||||
ejabberd_router:route(Local, Dest, Packet)
|
||||
end, Sessions).
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
|
||||
update_tables() ->
|
||||
|
||||
+357
-317
@@ -5,7 +5,7 @@
|
||||
%%% Created : 7 Oct 2006 by Magnus Henoch <henoch@dtek.chalmers.se>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -33,11 +33,13 @@
|
||||
-behaviour(gen_mod).
|
||||
|
||||
-export([read_caps/1,
|
||||
caps_stream_features/2,
|
||||
disco_features/5,
|
||||
disco_identity/5,
|
||||
disco_info/5,
|
||||
get_features/1]).
|
||||
get_caps/1,
|
||||
note_caps/3,
|
||||
wait_caps/2,
|
||||
clear_caps/1,
|
||||
get_features/2,
|
||||
get_user_resources/2,
|
||||
handle_disco_response/3]).
|
||||
|
||||
%% gen_mod callbacks
|
||||
-export([start/2, start_link/2,
|
||||
@@ -53,21 +55,120 @@
|
||||
]).
|
||||
|
||||
%% hook handlers
|
||||
-export([user_send_packet/3]).
|
||||
-export([receive_packet/3,
|
||||
receive_packet/4,
|
||||
presence_probe/3,
|
||||
remove_connection/3]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("jlib.hrl").
|
||||
|
||||
-define(PROCNAME, ejabberd_mod_caps).
|
||||
-define(DICT, dict).
|
||||
-define(CAPS_QUERY_TIMEOUT, 60000). % 1mn without answer, consider client never answer
|
||||
|
||||
-record(caps, {node, version, hash, exts}).
|
||||
-record(caps, {node, version, exts}).
|
||||
-record(caps_features, {node_pair, features = []}).
|
||||
-record(user_caps, {jid, caps}).
|
||||
-record(user_caps_resources, {uid, resource}).
|
||||
-record(state, {host,
|
||||
disco_requests = ?DICT:new(),
|
||||
feature_queries = []}).
|
||||
|
||||
-record(state, {host}).
|
||||
%% read_caps takes a list of XML elements (the child elements of a
|
||||
%% <presence/> 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([_ | Tail], Result) ->
|
||||
read_caps(Tail, Result);
|
||||
read_caps([], Result) ->
|
||||
Result.
|
||||
|
||||
%% get_caps reads user caps from database
|
||||
%% 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(LJID, Retry) ->
|
||||
case catch mnesia:dirty_read({user_caps, jid_to_binary(LJID)}) of
|
||||
[#user_caps{caps=waiting}] ->
|
||||
timer:sleep(2000),
|
||||
get_caps(LJID, Retry-1);
|
||||
[#user_caps{caps=Caps}] ->
|
||||
Caps;
|
||||
_ ->
|
||||
nothing
|
||||
end.
|
||||
|
||||
%% clear_caps removes user caps from database
|
||||
clear_caps(JID) ->
|
||||
{U, S, R} = jlib:jid_tolower(JID),
|
||||
BJID = jid_to_binary(JID),
|
||||
BUID = jid_to_binary({U, S, []}),
|
||||
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(LUser, LServer) ->
|
||||
case catch mnesia:dirty_read({user_caps_resources, jid_to_binary({LUser, LServer, []})}) 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
|
||||
%% 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) ->
|
||||
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
|
||||
%% 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.
|
||||
get_features(Host, Caps) ->
|
||||
case Caps of
|
||||
nothing ->
|
||||
[];
|
||||
#caps{} ->
|
||||
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||
gen_server:call(Proc, {get_features, Caps})
|
||||
end.
|
||||
|
||||
%%====================================================================
|
||||
%% API
|
||||
%%====================================================================
|
||||
start_link(Host, Opts) ->
|
||||
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||
gen_server:start_link({local, Proc}, ?MODULE, [Host, Opts], []).
|
||||
@@ -85,227 +186,61 @@ start(Host, Opts) ->
|
||||
|
||||
stop(Host) ->
|
||||
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||
gen_server:call(Proc, stop),
|
||||
supervisor:terminate_child(ejabberd_sup, Proc),
|
||||
supervisor:delete_child(ejabberd_sup, Proc).
|
||||
gen_server:call(Proc, stop).
|
||||
|
||||
%% get_features returns a list of features implied by the given caps
|
||||
%% record (as extracted by read_caps) or 'unknown' if features are
|
||||
%% not completely collected at the moment.
|
||||
get_features(nothing) ->
|
||||
[];
|
||||
get_features(#caps{node = Node, version = Version, exts = Exts}) ->
|
||||
SubNodes = [Version | Exts],
|
||||
lists:foldl(
|
||||
fun(SubNode, Acc) ->
|
||||
case mnesia:dirty_read({caps_features,
|
||||
node_to_binary(Node, SubNode)}) of
|
||||
[] ->
|
||||
Acc;
|
||||
[#caps_features{features = Features}] ->
|
||||
binary_to_features(Features) ++ Acc
|
||||
end
|
||||
end, [], SubNodes).
|
||||
|
||||
%% read_caps takes a list of XML elements (the child elements of a
|
||||
%% <presence/> 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),
|
||||
Hash = xml:get_attr_s("hash", Attrs),
|
||||
Exts = string:tokens(xml:get_attr_s("ext", Attrs), " "),
|
||||
read_caps(Tail, #caps{node = Node, hash = Hash,
|
||||
version = Version, exts = Exts});
|
||||
_ ->
|
||||
read_caps(Tail, Result)
|
||||
receive_packet(From, To, {xmlelement, "presence", Attrs, Els}) ->
|
||||
case xml:get_attr_s("type", Attrs) of
|
||||
"probe" ->
|
||||
ok;
|
||||
"error" ->
|
||||
ok;
|
||||
"invisible" ->
|
||||
ok;
|
||||
"subscribe" ->
|
||||
ok;
|
||||
"subscribed" ->
|
||||
ok;
|
||||
"unsubscribe" ->
|
||||
ok;
|
||||
"unsubscribed" ->
|
||||
ok;
|
||||
"unavailable" ->
|
||||
{_, S1, _} = jlib:jid_tolower(From),
|
||||
case jlib:jid_tolower(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
|
||||
_ ->
|
||||
note_caps(To#jid.lserver, From, read_caps(Els))
|
||||
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([_ | Tail], Result) ->
|
||||
read_caps(Tail, Result);
|
||||
read_caps([], Result) ->
|
||||
Result.
|
||||
|
||||
%%====================================================================
|
||||
%% Hooks
|
||||
%%====================================================================
|
||||
user_send_packet(#jid{luser = User, lserver = Server} = From,
|
||||
#jid{luser = User, lserver = Server, lresource = ""},
|
||||
{xmlelement, "presence", Attrs, Els}) ->
|
||||
Type = xml:get_attr_s("type", Attrs),
|
||||
if Type == ""; Type == "available" ->
|
||||
case read_caps(Els) of
|
||||
nothing ->
|
||||
ok;
|
||||
#caps{version = Version, exts = Exts} = Caps ->
|
||||
feature_request(Server, From, Caps, [Version | Exts])
|
||||
end;
|
||||
true ->
|
||||
ok
|
||||
end;
|
||||
user_send_packet(_From, _To, _Packet) ->
|
||||
receive_packet(_, _, _) ->
|
||||
ok.
|
||||
|
||||
caps_stream_features(Acc, MyHost) ->
|
||||
case make_my_disco_hash(MyHost) of
|
||||
"" ->
|
||||
Acc;
|
||||
Hash ->
|
||||
[{xmlelement, "c", [{"xmlns", ?NS_CAPS},
|
||||
{"hash", "sha-1"},
|
||||
{"node", ?EJABBERD_URI},
|
||||
{"ver", Hash}], []} | Acc]
|
||||
end.
|
||||
receive_packet(_JID, From, To, Packet) ->
|
||||
receive_packet(From, To, Packet).
|
||||
|
||||
disco_features(_Acc, From, To, ?EJABBERD_URI ++ "#" ++ [_|_], Lang) ->
|
||||
ejabberd_hooks:run_fold(disco_local_features,
|
||||
To#jid.lserver,
|
||||
empty,
|
||||
[From, To, "", Lang]);
|
||||
disco_features(Acc, _From, _To, _Node, _Lang) ->
|
||||
Acc.
|
||||
presence_probe(From, To, _) ->
|
||||
wait_caps(To#jid.lserver, From).
|
||||
|
||||
disco_identity(_Acc, From, To, ?EJABBERD_URI ++ "#" ++ [_|_], Lang) ->
|
||||
ejabberd_hooks:run_fold(disco_local_identity,
|
||||
To#jid.lserver,
|
||||
[],
|
||||
[From, To, "", Lang]);
|
||||
disco_identity(Acc, _From, _To, _Node, _Lang) ->
|
||||
Acc.
|
||||
remove_connection(_SID, JID, _Info) ->
|
||||
clear_caps(JID).
|
||||
|
||||
disco_info(_Acc, Host, Module, ?EJABBERD_URI ++ "#" ++ [_|_], Lang) ->
|
||||
ejabberd_hooks:run_fold(disco_info,
|
||||
Host,
|
||||
[],
|
||||
[Host, Module, "", Lang]);
|
||||
disco_info(Acc, _Host, _Module, _Node, _Lang) ->
|
||||
Acc.
|
||||
jid_to_binary(JID) ->
|
||||
{U, S, R} = jlib:jid_tolower(JID),
|
||||
list_to_binary(jlib:jid_to_string({U, S, R})).
|
||||
|
||||
%%====================================================================
|
||||
%% gen_server callbacks
|
||||
%%====================================================================
|
||||
init([Host, _Opts]) ->
|
||||
mnesia:create_table(caps_features,
|
||||
[{disc_copies, [node()]},
|
||||
{local_content, true},
|
||||
{attributes, record_info(fields, caps_features)}]),
|
||||
mnesia:add_table_copy(caps_features, node(), disc_copies),
|
||||
ejabberd_hooks:add(user_send_packet, Host,
|
||||
?MODULE, user_send_packet, 75),
|
||||
ejabberd_hooks:add(c2s_stream_features, Host,
|
||||
?MODULE, caps_stream_features, 75),
|
||||
ejabberd_hooks:add(s2s_stream_features, Host,
|
||||
?MODULE, caps_stream_features, 75),
|
||||
ejabberd_hooks:add(disco_local_features, Host,
|
||||
?MODULE, disco_features, 75),
|
||||
ejabberd_hooks:add(disco_local_identity, Host,
|
||||
?MODULE, disco_identity, 75),
|
||||
ejabberd_hooks:add(disco_info, Host,
|
||||
?MODULE, disco_info, 75),
|
||||
{ok, #state{host = Host}}.
|
||||
|
||||
handle_call(stop, _From, State) ->
|
||||
{stop, normal, ok, State};
|
||||
handle_call(_Req, _From, State) ->
|
||||
{reply, {error, badarg}, State}.
|
||||
|
||||
handle_cast(_Msg, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
handle_info(_Info, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
terminate(_Reason, State) ->
|
||||
Host = State#state.host,
|
||||
ejabberd_hooks:delete(user_send_packet, Host,
|
||||
?MODULE, user_send_packet, 75),
|
||||
ejabberd_hooks:delete(c2s_stream_features, Host,
|
||||
?MODULE, caps_stream_features, 75),
|
||||
ejabberd_hooks:delete(s2s_stream_features, Host,
|
||||
?MODULE, caps_stream_features, 75),
|
||||
ejabberd_hooks:delete(disco_local_features, Host,
|
||||
?MODULE, disco_features, 75),
|
||||
ejabberd_hooks:delete(disco_local_identity, Host,
|
||||
?MODULE, disco_identity, 75),
|
||||
ejabberd_hooks:delete(disco_info, Host,
|
||||
?MODULE, disco_info, 75),
|
||||
ok.
|
||||
|
||||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%====================================================================
|
||||
%% Aux functions
|
||||
%%====================================================================
|
||||
feature_request(Host, From, Caps, [SubNode | Tail] = SubNodes) ->
|
||||
Node = Caps#caps.node,
|
||||
BinaryNode = node_to_binary(Node, SubNode),
|
||||
case mnesia:dirty_read({caps_features, BinaryNode}) of
|
||||
[] ->
|
||||
IQ = #iq{type = get,
|
||||
xmlns = ?NS_DISCO_INFO,
|
||||
sub_el = [{xmlelement, "query",
|
||||
[{"xmlns", ?NS_DISCO_INFO},
|
||||
{"node", Node ++ "#" ++ SubNode}],
|
||||
[]}]},
|
||||
F = fun(IQReply) ->
|
||||
feature_response(
|
||||
IQReply, Host, From, Caps, SubNodes)
|
||||
end,
|
||||
ejabberd_local:route_iq(
|
||||
jlib:make_jid("", Host, ""), From, IQ, F);
|
||||
_ ->
|
||||
feature_request(Host, From, Caps, Tail)
|
||||
end;
|
||||
feature_request(_Host, _From, _Caps, []) ->
|
||||
ok.
|
||||
|
||||
feature_response(#iq{type = result,
|
||||
sub_el = [{xmlelement, _, _, Els}]},
|
||||
Host, From, Caps, [SubNode | SubNodes]) ->
|
||||
BinaryNode = node_to_binary(Caps#caps.node, SubNode),
|
||||
IsValid = case Caps#caps.hash of
|
||||
"sha-1" ->
|
||||
Caps#caps.version == make_disco_hash(Els, sha1);
|
||||
"md5" ->
|
||||
Caps#caps.version == make_disco_hash(Els, md5);
|
||||
_ ->
|
||||
true
|
||||
end,
|
||||
if IsValid ->
|
||||
Features = lists:flatmap(
|
||||
fun({xmlelement, "feature", FAttrs, _}) ->
|
||||
[xml:get_attr_s("var", FAttrs)];
|
||||
(_) ->
|
||||
[]
|
||||
end, Els),
|
||||
mnesia:dirty_write(
|
||||
#caps_features{node_pair = BinaryNode,
|
||||
features = features_to_binary(Features)});
|
||||
true ->
|
||||
mnesia:dirty_write(#caps_features{node_pair = BinaryNode})
|
||||
end,
|
||||
feature_request(Host, From, Caps, SubNodes);
|
||||
feature_response(timeout, _Host, _From, _Caps, _SubNodes) ->
|
||||
ok;
|
||||
feature_response(_IQResult, Host, From, Caps, [SubNode | SubNodes]) ->
|
||||
%% We got type=error or invalid type=result stanza, so
|
||||
%% we cache empty feature not to probe the client permanently
|
||||
BinaryNode = node_to_binary(Caps#caps.node, SubNode),
|
||||
mnesia:dirty_write(#caps_features{node_pair = BinaryNode}),
|
||||
feature_request(Host, From, Caps, SubNodes).
|
||||
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)}.
|
||||
@@ -313,101 +248,206 @@ node_to_binary(Node, SubNode) ->
|
||||
features_to_binary(L) -> [list_to_binary(I) || I <- L].
|
||||
binary_to_features(L) -> [binary_to_list(I) || I <- L].
|
||||
|
||||
make_my_disco_hash(Host) ->
|
||||
JID = jlib:make_jid("", Host, ""),
|
||||
case {ejabberd_hooks:run_fold(disco_local_features,
|
||||
Host,
|
||||
empty,
|
||||
[JID, JID, "", ""]),
|
||||
ejabberd_hooks:run_fold(disco_local_identity,
|
||||
Host,
|
||||
[],
|
||||
[JID, JID, "", ""]),
|
||||
ejabberd_hooks:run_fold(disco_info,
|
||||
Host,
|
||||
[],
|
||||
[Host, undefined, "", ""])} of
|
||||
{{result, Features}, Identities, Info} ->
|
||||
Feats = lists:map(
|
||||
fun({{Feat, _Host}}) ->
|
||||
{xmlelement, "feature", [{"var", Feat}], []};
|
||||
(Feat) ->
|
||||
{xmlelement, "feature", [{"var", Feat}], []}
|
||||
end, Features),
|
||||
make_disco_hash(Identities ++ Info ++ Feats, sha1);
|
||||
_Err ->
|
||||
""
|
||||
%%====================================================================
|
||||
%% gen_server callbacks
|
||||
%%====================================================================
|
||||
|
||||
init([Host, _Opts]) ->
|
||||
mnesia:create_table(caps_features,
|
||||
[{disc_copies, [node()]},
|
||||
{attributes, record_info(fields, caps_features)}]),
|
||||
mnesia:create_table(user_caps,
|
||||
[{ram_copies, [node()]},
|
||||
{attributes, record_info(fields, user_caps)}]),
|
||||
mnesia:create_table(user_caps_resources,
|
||||
[{ram_copies, [node()]},
|
||||
{type, bag},
|
||||
{attributes, record_info(fields, user_caps_resources)}]),
|
||||
mnesia:delete_table(user_caps_default),
|
||||
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),
|
||||
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}) ->
|
||||
SubNodes = [Version | Exts],
|
||||
%% 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.
|
||||
|
||||
make_disco_hash(DiscoEls, Algo) when Algo == sha1; Algo == md5 ->
|
||||
Concat = [concat_identities(DiscoEls),
|
||||
concat_features(DiscoEls),
|
||||
concat_info(DiscoEls)],
|
||||
base64:encode_to_string(
|
||||
if Algo == sha1 ->
|
||||
crypto:sha(Concat);
|
||||
Algo == md5 ->
|
||||
crypto:md5(Concat)
|
||||
end).
|
||||
timestamp() ->
|
||||
{MegaSecs, Secs, _MicroSecs} = now(),
|
||||
MegaSecs * 1000000 + Secs.
|
||||
|
||||
concat_features(Els) ->
|
||||
lists:usort(
|
||||
lists:flatmap(
|
||||
fun({xmlelement, "feature", Attrs, _}) ->
|
||||
[[xml:get_attr_s("var", Attrs), $<]];
|
||||
(_) ->
|
||||
[]
|
||||
end, Els)).
|
||||
handle_call({get_features, Caps}, From, State) ->
|
||||
case maybe_get_features(Caps) of
|
||||
{ok, Features} ->
|
||||
{reply, binary_to_features(Features), State};
|
||||
wait ->
|
||||
gen_server:cast(self(), visit_feature_queries),
|
||||
Timeout = timestamp() + 10,
|
||||
FeatureQueries = State#state.feature_queries,
|
||||
NewFeatureQueries = [{From, Caps, Timeout} | FeatureQueries],
|
||||
NewState = State#state{feature_queries = NewFeatureQueries},
|
||||
{noreply, NewState}
|
||||
end;
|
||||
|
||||
concat_identities(Els) ->
|
||||
lists:sort(
|
||||
lists:flatmap(
|
||||
fun({xmlelement, "identity", Attrs, _}) ->
|
||||
[[xml:get_attr_s("category", Attrs), $/,
|
||||
xml:get_attr_s("type", Attrs), $/,
|
||||
xml:get_attr_s("xml:lang", Attrs), $/,
|
||||
xml:get_attr_s("name", Attrs), $<]];
|
||||
(_) ->
|
||||
[]
|
||||
end, Els)).
|
||||
handle_call(stop, _From, State) ->
|
||||
{stop, normal, ok, State}.
|
||||
|
||||
concat_info(Els) ->
|
||||
lists:sort(
|
||||
lists:flatmap(
|
||||
fun({xmlelement, "x", Attrs, Fields}) ->
|
||||
case {xml:get_attr_s("xmlns", Attrs),
|
||||
xml:get_attr_s("type", Attrs)} of
|
||||
{?NS_XDATA, "result"} ->
|
||||
[concat_xdata_fields(Fields)];
|
||||
_ ->
|
||||
[]
|
||||
end;
|
||||
(_) ->
|
||||
[]
|
||||
end, Els)).
|
||||
handle_cast({note_caps, From, nothing}, State) ->
|
||||
BJID = 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) ->
|
||||
%% XXX: this leads to race conditions where ejabberd will send
|
||||
%% lots of caps disco requests.
|
||||
{U, S, R} = jlib:jid_tolower(From),
|
||||
BJID = jid_to_binary(From),
|
||||
mnesia:transaction(fun() ->
|
||||
mnesia:write(#user_caps{jid = BJID, caps = caps_to_binary(Caps)}),
|
||||
case ejabberd_sm:get_user_resources(U, S) of
|
||||
[] ->
|
||||
% only store resources of caps aware external contacts
|
||||
BUID = jid_to_binary({U, S, []}),
|
||||
mnesia: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) ->
|
||||
case mnesia:dirty_read({caps_features, node_to_binary(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) ->
|
||||
ID = randoms:get_string(),
|
||||
Stanza =
|
||||
{xmlelement, "iq",
|
||||
[{"type", "get"},
|
||||
{"id", ID}],
|
||||
[{xmlelement, "query",
|
||||
[{"xmlns", ?NS_DISCO_INFO},
|
||||
{"node", lists:concat([Node, "#", SubNode])}],
|
||||
[]}]},
|
||||
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, BJID}),
|
||||
?DICT:store(ID, node_to_binary(Node, SubNode), Dict)
|
||||
end, Requests, Missing),
|
||||
{noreply, State#state{disco_requests = NewRequests}}
|
||||
end;
|
||||
handle_cast({wait_caps, From}, State) ->
|
||||
BJID = jid_to_binary(From),
|
||||
mnesia:dirty_write(#user_caps{jid = BJID, caps = waiting}),
|
||||
{noreply, State};
|
||||
handle_cast({disco_response, From, _To,
|
||||
#iq{type = Type, id = ID,
|
||||
sub_el = SubEls}},
|
||||
#state{disco_requests = Requests} = State) ->
|
||||
case {Type, SubEls} of
|
||||
{result, [{xmlelement, "query", _Attrs, Els}]} ->
|
||||
case ?DICT:find(ID, Requests) of
|
||||
{ok, BinaryNode} ->
|
||||
Features =
|
||||
lists:flatmap(fun({xmlelement, "feature", FAttrs, _}) ->
|
||||
[xml:get_attr_s("var", FAttrs)];
|
||||
(_) ->
|
||||
[]
|
||||
end, Els),
|
||||
mnesia:dirty_write(#caps_features{node_pair = BinaryNode, features = features_to_binary(Features)}),
|
||||
gen_server:cast(self(), visit_feature_queries);
|
||||
error ->
|
||||
?DEBUG("ID '~s' matches no query", [ID])
|
||||
end;
|
||||
{error, _} ->
|
||||
%% XXX: if we get error, we cache empty feature not to probe the client continuously
|
||||
case ?DICT:find(ID, Requests) of
|
||||
{ok, BinaryNode} ->
|
||||
mnesia:dirty_write(#caps_features{node_pair = BinaryNode}),
|
||||
gen_server:cast(self(), visit_feature_queries);
|
||||
error ->
|
||||
?DEBUG("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]);
|
||||
{result, _} ->
|
||||
?DEBUG("Invalid IQ contents from ~s:~n~p", [jlib:jid_to_string(From), SubEls]);
|
||||
_ ->
|
||||
%% Can't do anything about errors
|
||||
ok
|
||||
end,
|
||||
NewRequests = ?DICT:erase(ID, Requests),
|
||||
{noreply, State#state{disco_requests = NewRequests}};
|
||||
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(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 =
|
||||
lists:foldl(fun({From, Caps, Timeout}, Acc) ->
|
||||
case maybe_get_features(Caps) of
|
||||
wait when Timeout > Timestamp -> [{From, Caps, Timeout} | Acc];
|
||||
wait -> Acc;
|
||||
{ok, Features} ->
|
||||
gen_server:reply(From, Features),
|
||||
Acc
|
||||
end
|
||||
end, [], FeatureQueries),
|
||||
{noreply, State#state{feature_queries = NewFeatureQueries}}.
|
||||
|
||||
concat_xdata_fields(Fields) ->
|
||||
[Form, Res] =
|
||||
lists:foldl(
|
||||
fun({xmlelement, "field", Attrs, Els} = El,
|
||||
[FormType, VarFields] = Acc) ->
|
||||
case xml:get_attr_s("var", Attrs) of
|
||||
"" ->
|
||||
Acc;
|
||||
"FORM_TYPE" ->
|
||||
[xml:get_subtag_cdata(El, "value"), VarFields];
|
||||
Var ->
|
||||
[FormType,
|
||||
[[[Var, $<],
|
||||
lists:sort(
|
||||
lists:flatmap(
|
||||
fun({xmlelement, "value", _, VEls}) ->
|
||||
[[xml:get_cdata(VEls), $<]];
|
||||
(_) ->
|
||||
[]
|
||||
end, Els))] | VarFields]]
|
||||
end;
|
||||
(_, Acc) ->
|
||||
Acc
|
||||
end, ["", []], Fields),
|
||||
[Form, $<, lists:sort(Res)].
|
||||
handle_disco_response(From, To, IQ) ->
|
||||
#jid{lserver = Host} = To,
|
||||
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||
gen_server:cast(Proc, {disco_response, From, To, IQ}).
|
||||
|
||||
handle_info(_Info, State) ->
|
||||
{noreply, 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),
|
||||
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) ->
|
||||
{ok, State}.
|
||||
|
||||
+3
-35
@@ -5,7 +5,7 @@
|
||||
%%% Created : 19 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -237,23 +237,7 @@ get_local_features(Acc, From, #jid{lserver = LServer} = _To, Node, _Lang) ->
|
||||
?INFO_RESULT(Allow, [?NS_COMMANDS]);
|
||||
["config", _] ->
|
||||
?INFO_RESULT(Allow, [?NS_COMMANDS]);
|
||||
?NS_ADMINL("add-user") ->
|
||||
?INFO_RESULT(Allow, [?NS_COMMANDS]);
|
||||
?NS_ADMINL("delete-user") ->
|
||||
?INFO_RESULT(Allow, [?NS_COMMANDS]);
|
||||
?NS_ADMINL("end-user-session") ->
|
||||
?INFO_RESULT(Allow, [?NS_COMMANDS]);
|
||||
?NS_ADMINL("get-user-password") ->
|
||||
?INFO_RESULT(Allow, [?NS_COMMANDS]);
|
||||
?NS_ADMINL("change-user-password") ->
|
||||
?INFO_RESULT(Allow, [?NS_COMMANDS]);
|
||||
?NS_ADMINL("get-user-lastlogin") ->
|
||||
?INFO_RESULT(Allow, [?NS_COMMANDS]);
|
||||
?NS_ADMINL("user-stats") ->
|
||||
?INFO_RESULT(Allow, [?NS_COMMANDS]);
|
||||
?NS_ADMINL("get-registered-users-num") ->
|
||||
?INFO_RESULT(Allow, [?NS_COMMANDS]);
|
||||
?NS_ADMINL("get-online-users-num") ->
|
||||
["http:" | _] ->
|
||||
?INFO_RESULT(Allow, [?NS_COMMANDS]);
|
||||
_ ->
|
||||
Acc
|
||||
@@ -465,23 +449,7 @@ get_local_items(Acc, From, #jid{lserver = LServer} = To, Node, Lang) ->
|
||||
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
|
||||
["config", _] ->
|
||||
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
|
||||
?NS_ADMINL("add-user") ->
|
||||
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
|
||||
?NS_ADMINL("delete-user") ->
|
||||
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
|
||||
?NS_ADMINL("end-user-session") ->
|
||||
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
|
||||
?NS_ADMINL("get-user-password") ->
|
||||
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
|
||||
?NS_ADMINL("change-user-password") ->
|
||||
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
|
||||
?NS_ADMINL("get-user-lastlogin") ->
|
||||
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
|
||||
?NS_ADMINL("user-stats") ->
|
||||
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
|
||||
?NS_ADMINL("get-registered-users-num") ->
|
||||
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
|
||||
?NS_ADMINL("get-online-users-num") ->
|
||||
?NS_ADMINL(_) ->
|
||||
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
|
||||
_ ->
|
||||
Acc
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%%% Created : 26 Oct 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
+61
-103
@@ -5,7 +5,7 @@
|
||||
%%% Created : 1 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
@@ -172,7 +172,7 @@ process_local_iq_info(From, To, #iq{type = Type, lang = Lang,
|
||||
[{"xmlns", ?NS_DISCO_INFO} | ANode],
|
||||
Identity ++
|
||||
Info ++
|
||||
features_to_xml(Features)
|
||||
lists:map(fun feature_to_xml/1, Features)
|
||||
}]};
|
||||
{error, Error} ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, Error]}
|
||||
@@ -209,16 +209,10 @@ get_local_features(Acc, _From, _To, _Node, _Lang) ->
|
||||
end.
|
||||
|
||||
|
||||
features_to_xml(FeatureList) ->
|
||||
%% Avoid duplicating features
|
||||
[{xmlelement, "feature", [{"var", Feat}], []} ||
|
||||
Feat <- lists:usort(
|
||||
lists:map(
|
||||
fun({{Feature, _Host}}) ->
|
||||
Feature;
|
||||
(Feature) when is_list(Feature) ->
|
||||
Feature
|
||||
end, FeatureList))].
|
||||
feature_to_xml({{Feature, _Host}}) ->
|
||||
feature_to_xml(Feature);
|
||||
feature_to_xml(Feature) when is_list(Feature) ->
|
||||
{xmlelement, "feature", [{"var", Feature}], []}.
|
||||
|
||||
domain_to_xml({Domain}) ->
|
||||
{xmlelement, "item", [{"jid", Domain}], []};
|
||||
@@ -269,48 +263,42 @@ process_sm_iq_items(From, To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ
|
||||
set ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
|
||||
get ->
|
||||
case is_presence_subscribed(From, To) of
|
||||
true ->
|
||||
Host = To#jid.lserver,
|
||||
Node = xml:get_tag_attr_s("node", SubEl),
|
||||
case ejabberd_hooks:run_fold(disco_sm_items,
|
||||
Host,
|
||||
empty,
|
||||
[From, To, Node, Lang]) of
|
||||
{result, Items} ->
|
||||
ANode = case Node of
|
||||
"" -> [];
|
||||
_ -> [{"node", Node}]
|
||||
end,
|
||||
IQ#iq{type = result,
|
||||
sub_el = [{xmlelement, "query",
|
||||
[{"xmlns", ?NS_DISCO_ITEMS} | ANode],
|
||||
Items
|
||||
}]};
|
||||
{error, Error} ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, Error]}
|
||||
end;
|
||||
false ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_SERVICE_UNAVAILABLE]}
|
||||
end
|
||||
Host = To#jid.lserver,
|
||||
Node = xml:get_tag_attr_s("node", SubEl),
|
||||
case ejabberd_hooks:run_fold(disco_sm_items,
|
||||
Host,
|
||||
empty,
|
||||
[From, To, Node, Lang]) of
|
||||
{result, Items} ->
|
||||
ANode = case Node of
|
||||
"" -> [];
|
||||
_ -> [{"node", Node}]
|
||||
end,
|
||||
IQ#iq{type = result,
|
||||
sub_el = [{xmlelement, "query",
|
||||
[{"xmlns", ?NS_DISCO_ITEMS} | ANode],
|
||||
Items
|
||||
}]};
|
||||
{error, Error} ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, Error]}
|
||||
end
|
||||
end.
|
||||
|
||||
get_sm_items({error, _Error} = Acc, _From, _To, _Node, _Lang) ->
|
||||
Acc;
|
||||
|
||||
get_sm_items(Acc, From,
|
||||
#jid{user = User, server = Server} = To,
|
||||
get_sm_items(Acc,
|
||||
#jid{luser = LFrom, lserver = LSFrom},
|
||||
#jid{user = User, server = Server, luser = LTo, lserver = LSTo} = _To,
|
||||
[], _Lang) ->
|
||||
Items = case Acc of
|
||||
{result, Its} -> Its;
|
||||
empty -> []
|
||||
end,
|
||||
Items1 = case is_presence_subscribed(From, To) of
|
||||
true ->
|
||||
get_user_resources(User, Server);
|
||||
_ ->
|
||||
[]
|
||||
end,
|
||||
Items1 = case {LFrom, LSFrom} of
|
||||
{LTo, LSTo} -> get_user_resources(User, Server);
|
||||
_ -> []
|
||||
end,
|
||||
{result, Items ++ Items1};
|
||||
|
||||
get_sm_items({result, _} = Acc, _From, _To, _Node, _Lang) ->
|
||||
@@ -326,63 +314,39 @@ get_sm_items(empty, From, To, _Node, _Lang) ->
|
||||
{error, ?ERR_NOT_ALLOWED}
|
||||
end.
|
||||
|
||||
is_presence_subscribed(#jid{luser=User, lserver=Server}, #jid{luser=LUser, lserver=LServer}) ->
|
||||
lists:any(fun({roster, _, _, {TUser, TServer, _}, _, S, _, _, _, _}) ->
|
||||
if
|
||||
LUser == TUser, LServer == TServer, S/=none ->
|
||||
true;
|
||||
true ->
|
||||
false
|
||||
end
|
||||
end,
|
||||
ejabberd_hooks:run_fold(roster_get, Server, [], [{User, Server}]))
|
||||
orelse User == LUser andalso Server == LServer.
|
||||
|
||||
process_sm_iq_info(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 ->
|
||||
case is_presence_subscribed(From, To) of
|
||||
true ->
|
||||
Host = To#jid.lserver,
|
||||
Node = xml:get_tag_attr_s("node", SubEl),
|
||||
Identity = ejabberd_hooks:run_fold(disco_sm_identity,
|
||||
Host,
|
||||
[],
|
||||
[From, To, Node, Lang]),
|
||||
case ejabberd_hooks:run_fold(disco_sm_features,
|
||||
Host,
|
||||
empty,
|
||||
[From, To, Node, Lang]) of
|
||||
{result, Features} ->
|
||||
ANode = case Node of
|
||||
"" -> [];
|
||||
_ -> [{"node", Node}]
|
||||
end,
|
||||
IQ#iq{type = result,
|
||||
sub_el = [{xmlelement, "query",
|
||||
[{"xmlns", ?NS_DISCO_INFO} | ANode],
|
||||
Identity ++
|
||||
features_to_xml(Features)
|
||||
}]};
|
||||
{error, Error} ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, Error]}
|
||||
end;
|
||||
false ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_SERVICE_UNAVAILABLE]}
|
||||
end
|
||||
end.
|
||||
|
||||
get_sm_identity(Acc, _From, #jid{luser = LUser, lserver=LServer}, _Node, _Lang) ->
|
||||
Acc ++ case ejabberd_auth:is_user_exists(LUser, LServer) of
|
||||
true ->
|
||||
[{xmlelement, "identity", [{"category", "account"},
|
||||
{"type", "registered"}], []}];
|
||||
_ ->
|
||||
[]
|
||||
Host = To#jid.lserver,
|
||||
Node = xml:get_tag_attr_s("node", SubEl),
|
||||
Identity = ejabberd_hooks:run_fold(disco_sm_identity,
|
||||
Host,
|
||||
[],
|
||||
[From, To, Node, Lang]),
|
||||
case ejabberd_hooks:run_fold(disco_sm_features,
|
||||
Host,
|
||||
empty,
|
||||
[From, To, Node, Lang]) of
|
||||
{result, Features} ->
|
||||
ANode = case Node of
|
||||
"" -> [];
|
||||
_ -> [{"node", Node}]
|
||||
end,
|
||||
IQ#iq{type = result,
|
||||
sub_el = [{xmlelement, "query",
|
||||
[{"xmlns", ?NS_DISCO_INFO} | ANode],
|
||||
Identity ++
|
||||
lists:map(fun feature_to_xml/1, Features)
|
||||
}]};
|
||||
{error, Error} ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, Error]}
|
||||
end
|
||||
end.
|
||||
|
||||
get_sm_identity(Acc, _From, _To, _Node, _Lang) ->
|
||||
Acc.
|
||||
|
||||
get_sm_features(empty, From, To, _Node, _Lang) ->
|
||||
#jid{luser = LFrom, lserver = LSFrom} = From,
|
||||
@@ -409,13 +373,7 @@ get_user_resources(User, Server) ->
|
||||
|
||||
%%% Support for: XEP-0157 Contact Addresses for XMPP Services
|
||||
|
||||
get_info(_A, Host, Mod, Node, _Lang) when Node == [] ->
|
||||
Module = case Mod of
|
||||
undefined ->
|
||||
?MODULE;
|
||||
_ ->
|
||||
Mod
|
||||
end,
|
||||
get_info(_A, Host, Module, Node, _Lang) when Node == [] ->
|
||||
Serverinfo_fields = get_fields_xml(Host, Module),
|
||||
[{xmlelement, "x",
|
||||
[{"xmlns", ?NS_XDATA}, {"type", "result"}],
|
||||
@@ -429,8 +387,8 @@ get_info(_A, Host, Mod, Node, _Lang) when Node == [] ->
|
||||
++ Serverinfo_fields
|
||||
}];
|
||||
|
||||
get_info(Acc, _, _, _Node, _) ->
|
||||
Acc.
|
||||
get_info(_, _, _, _Node, _) ->
|
||||
[].
|
||||
|
||||
get_fields_xml(Host, Module) ->
|
||||
Fields = gen_mod:get_module_opt(Host, ?MODULE, server_info, []),
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
%%% Created : 15 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
%%% {mod_ip_blacklist, []}
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2010 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
|
||||
|
||||
@@ -24,7 +24,7 @@ EFLAGS += -pz ..
|
||||
|
||||
# make debug=true to compile Erlang module with debug informations.
|
||||
ifdef debug
|
||||
EFLAGS+=+debug_info +export_all
|
||||
EFLAGS+=+debug_info
|
||||
endif
|
||||
|
||||
ERLSHLIBS = ../iconv_erl.so
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user