mirror of
https://github.com/processone/ejabberd.git
synced 2024-12-24 17:29:28 +01:00
Merge branch '2.2.x' of git+ssh://gitorious.process-one.net/+ejabberd-developers/ejabberd/maincustomers into 2.2.x
This commit is contained in:
commit
1dfd9fd568
2
README
2
README
@ -20,7 +20,7 @@ To compile ejabberd you need:
|
|||||||
- GNU Iconv 1.8 or higher, for the IRC Transport
|
- GNU Iconv 1.8 or higher, for the IRC Transport
|
||||||
(mod_irc). Optional. Not needed on systems with GNU Libc.
|
(mod_irc). Optional. Not needed on systems with GNU Libc.
|
||||||
- ImageMagick's Convert program. Optional. For CAPTCHA challenges.
|
- ImageMagick's Convert program. Optional. For CAPTCHA challenges.
|
||||||
- exmpp 0.9.2 or higher. Optional. For import/export XEP-0227 files.
|
- exmpp 0.9.6 or higher. Optional. For import/export XEP-0227 files.
|
||||||
|
|
||||||
|
|
||||||
1. Compile and install on *nix systems
|
1. Compile and install on *nix systems
|
||||||
|
@ -356,7 +356,7 @@ Don’t use R14A or R14B because <A HREF="http://www.erlang.org/cgi-bin/ezm
|
|||||||
</LI><LI CLASS="li-itemize">PAM library. Optional. For Pluggable Authentication Modules (PAM). See section <A HREF="#pam">3.1.4</A>.
|
</LI><LI CLASS="li-itemize">PAM library. Optional. For Pluggable Authentication Modules (PAM). See section <A HREF="#pam">3.1.4</A>.
|
||||||
</LI><LI CLASS="li-itemize">GNU Iconv 1.8 or higher, for the IRC Transport (mod_irc). Optional. Not needed on systems with GNU Libc. See section <A HREF="#modirc">3.3.8</A>.
|
</LI><LI CLASS="li-itemize">GNU Iconv 1.8 or higher, for the IRC Transport (mod_irc). Optional. Not needed on systems with GNU Libc. See section <A HREF="#modirc">3.3.8</A>.
|
||||||
</LI><LI CLASS="li-itemize">ImageMagick’s Convert program. Optional. For CAPTCHA challenges. See section <A HREF="#captcha">3.1.8</A>.
|
</LI><LI CLASS="li-itemize">ImageMagick’s Convert program. Optional. For CAPTCHA challenges. See section <A HREF="#captcha">3.1.8</A>.
|
||||||
</LI><LI CLASS="li-itemize">exmpp 0.9.2 or higher. Optional. For import/export user data with <A HREF="http://xmpp.org/extensions/xep-0227.html">XEP-0227</A> XML files.
|
</LI><LI CLASS="li-itemize">exmpp 0.9.6 or higher. Optional. For import/export user data with <A HREF="http://xmpp.org/extensions/xep-0227.html">XEP-0227</A> XML files.
|
||||||
</LI></UL><P> <A NAME="download"></A> </P><!--TOC subsection Download Source Code-->
|
</LI></UL><P> <A NAME="download"></A> </P><!--TOC subsection Download Source Code-->
|
||||||
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc10">2.4.2</A>  <A HREF="#download">Download Source Code</A></H3><!--SEC END --><P> <A NAME="download"></A>
|
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc10">2.4.2</A>  <A HREF="#download">Download Source Code</A></H3><!--SEC END --><P> <A NAME="download"></A>
|
||||||
</P><P>Released versions of <TT>ejabberd</TT> are available in the ProcessOne <TT>ejabberd</TT> downloads page:
|
</P><P>Released versions of <TT>ejabberd</TT> are available in the ProcessOne <TT>ejabberd</TT> downloads page:
|
||||||
@ -2994,7 +2994,7 @@ The default option value is an empty list: <TT>[]</TT>.
|
|||||||
This option sets the minimum informational entropy for passwords. The value <TT>Entropy</TT>
|
This option sets the minimum informational entropy for passwords. The value <TT>Entropy</TT>
|
||||||
is a number of bits of entropy. The recommended minimum is 32 bits.
|
is a number of bits of entropy. The recommended minimum is 32 bits.
|
||||||
The default is 0, i.e. no checks are performed.
|
The default is 0, i.e. no checks are performed.
|
||||||
</DD><DT CLASS="dt-description"><B><TT>{welcome_message, Message}</TT></B></DT><DD CLASS="dd-description"> Set a welcome message that
|
</DD><DT CLASS="dt-description"><B><TT>{welcome_message, {Subject, Body}}</TT></B></DT><DD CLASS="dd-description"> Set a welcome message that
|
||||||
is sent to each newly registered account. The first string is the subject, and
|
is sent to each newly registered account. The first string is the subject, and
|
||||||
the second string is the message body.
|
the second string is the message body.
|
||||||
In the body you can set a newline with the characters: <CODE>\n</CODE>
|
In the body you can set a newline with the characters: <CODE>\n</CODE>
|
||||||
|
@ -66,6 +66,7 @@
|
|||||||
\newcommand{\module}[1]{\texttt{#1}}
|
\newcommand{\module}[1]{\texttt{#1}}
|
||||||
\newcommand{\modadhoc}{\module{mod\_adhoc}}
|
\newcommand{\modadhoc}{\module{mod\_adhoc}}
|
||||||
\newcommand{\modannounce}{\module{mod\_announce}}
|
\newcommand{\modannounce}{\module{mod\_announce}}
|
||||||
|
\newcommand{\modblocking}{\module{mod\_blocking}}
|
||||||
\newcommand{\modcaps}{\module{mod\_caps}}
|
\newcommand{\modcaps}{\module{mod\_caps}}
|
||||||
\newcommand{\modconfigure}{\module{mod\_configure}}
|
\newcommand{\modconfigure}{\module{mod\_configure}}
|
||||||
\newcommand{\moddisco}{\module{mod\_disco}}
|
\newcommand{\moddisco}{\module{mod\_disco}}
|
||||||
@ -80,6 +81,7 @@
|
|||||||
\newcommand{\modoffline}{\module{mod\_offline}}
|
\newcommand{\modoffline}{\module{mod\_offline}}
|
||||||
\newcommand{\modofflineodbc}{\module{mod\_offline\_odbc}}
|
\newcommand{\modofflineodbc}{\module{mod\_offline\_odbc}}
|
||||||
\newcommand{\modping}{\module{mod\_ping}}
|
\newcommand{\modping}{\module{mod\_ping}}
|
||||||
|
\newcommand{\modprescounter}{\module{mod\_pres\_counter}}
|
||||||
\newcommand{\modprivacy}{\module{mod\_privacy}}
|
\newcommand{\modprivacy}{\module{mod\_privacy}}
|
||||||
\newcommand{\modprivacyodbc}{\module{mod\_privacy\_odbc}}
|
\newcommand{\modprivacyodbc}{\module{mod\_privacy\_odbc}}
|
||||||
\newcommand{\modprivate}{\module{mod\_private}}
|
\newcommand{\modprivate}{\module{mod\_private}}
|
||||||
@ -321,7 +323,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 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 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 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.6 or higher. Optional. For import/export user data with \xepref{0227} XML files.
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
|
|
||||||
\makesubsection{download}{Download Source Code}
|
\makesubsection{download}{Download Source Code}
|
||||||
@ -1030,7 +1032,7 @@ However, the c2s and s2s connections to the domain \term{example.com} use the fi
|
|||||||
\item Port 5269 listens for s2s connections with STARTTLS. The socket is set for IPv6 instead of IPv4.
|
\item Port 5269 listens for s2s connections with STARTTLS. The socket is set for IPv6 instead of IPv4.
|
||||||
\item Port 3478 listens for STUN requests over UDP.
|
\item Port 3478 listens for STUN requests over UDP.
|
||||||
\item Port 5280 listens for HTTP requests, and serves the HTTP Poll service.
|
\item Port 5280 listens for HTTP requests, and serves the HTTP Poll service.
|
||||||
\item Port 5281 listens for HTTP requests, and serves the Web Admin using HTTPS as explained in
|
\item Port 5281 listens for HTTP requests, using HTTPS to serve HTTP-Bind (BOSH) and the Web Admin as explained in
|
||||||
section~\ref{webadmin}. The socket only listens connections to the IP address 127.0.0.1.
|
section~\ref{webadmin}. The socket only listens connections to the IP address 127.0.0.1.
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
@ -1059,6 +1061,7 @@ However, the c2s and s2s connections to the domain \term{example.com} use the fi
|
|||||||
]},
|
]},
|
||||||
{{5281, "127.0.0.1"}, ejabberd_http, [
|
{{5281, "127.0.0.1"}, ejabberd_http, [
|
||||||
web_admin,
|
web_admin,
|
||||||
|
http_bind,
|
||||||
tls, {certfile, "/etc/ejabberd/server.pem"},
|
tls, {certfile, "/etc/ejabberd/server.pem"},
|
||||||
]}
|
]}
|
||||||
]
|
]
|
||||||
@ -1635,11 +1638,14 @@ The configurable options are:
|
|||||||
\titem{\{captcha\_cmd, Path\}}
|
\titem{\{captcha\_cmd, Path\}}
|
||||||
Full path to a script that generates the image.
|
Full path to a script that generates the image.
|
||||||
The default value is an empty string: \term{""}
|
The default value is an empty string: \term{""}
|
||||||
\titem{\{captcha\_host, Host\}}
|
\titem{\{captcha\_host, ProtocolHostPort\}}
|
||||||
Host part of the URL sent to the user.
|
ProtocolHostPort is a string with the host, and optionally the Protocol and Port number.
|
||||||
You can include the port number.
|
It must identify where ejabberd listens for CAPTCHA requests.
|
||||||
The URL sent to the user is formed by: \term{http://Host/captcha/}
|
The URL sent to the user is formed by: \term{Protocol://Host:Port/captcha/}
|
||||||
The default value is the first hostname configured.
|
The default value is: protocol \term{http}, the first hostname configured, and port \term{80}.
|
||||||
|
If you specify a port number that does not match exactly an ejabberd listener
|
||||||
|
(because you are using a reverse proxy or other port-forwarding tool),
|
||||||
|
then you must specify the transfer protocol, as seen in the example below.
|
||||||
\end{description}
|
\end{description}
|
||||||
|
|
||||||
Additionally, an \term{ejabberd\_http} listener must be enabled with the \term{captcha} option.
|
Additionally, an \term{ejabberd\_http} listener must be enabled with the \term{captcha} option.
|
||||||
@ -1651,6 +1657,8 @@ Example configuration:
|
|||||||
|
|
||||||
{captcha_cmd, "/lib/ejabberd/priv/bin/captcha.sh"}.
|
{captcha_cmd, "/lib/ejabberd/priv/bin/captcha.sh"}.
|
||||||
{captcha_host, "example.org:5280"}.
|
{captcha_host, "example.org:5280"}.
|
||||||
|
%% {captcha_host, "https://example.org:443"}.
|
||||||
|
%% {captcha_host, "http://example.com"}.
|
||||||
|
|
||||||
{listen,
|
{listen,
|
||||||
[
|
[
|
||||||
@ -1863,6 +1871,7 @@ The following LDAP servers are tested with \ejabberd{}:
|
|||||||
\item \footahref{http://www.microsoft.com/activedirectory/}{Active Directory}
|
\item \footahref{http://www.microsoft.com/activedirectory/}{Active Directory}
|
||||||
(see section~\ref{ad})
|
(see section~\ref{ad})
|
||||||
\item \footahref{http://www.openldap.org/}{OpenLDAP}
|
\item \footahref{http://www.openldap.org/}{OpenLDAP}
|
||||||
|
\item \footahref{http://www.communigate.com/}{CommuniGate Pro}
|
||||||
\item Normally any LDAP compatible server should work; inform us about your
|
\item Normally any LDAP compatible server should work; inform us about your
|
||||||
success with a not-listed server so that we can list it here.
|
success with a not-listed server so that we can list it here.
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
@ -2526,6 +2535,7 @@ The following table lists all modules included in \ejabberd{}.
|
|||||||
\hline
|
\hline
|
||||||
\hline \modadhoc{} & Ad-Hoc Commands (\xepref{0050}) & \\
|
\hline \modadhoc{} & Ad-Hoc Commands (\xepref{0050}) & \\
|
||||||
\hline \ahrefloc{modannounce}{\modannounce{}} & Manage announcements & recommends \modadhoc{} \\
|
\hline \ahrefloc{modannounce}{\modannounce{}} & Manage announcements & recommends \modadhoc{} \\
|
||||||
|
\hline \modblocking{} & Simple Communications Blocking (\xepref{0191}) & \modprivacy{} \\
|
||||||
\hline \modcaps{} & Entity Capabilities (\xepref{0115}) & \\
|
\hline \modcaps{} & Entity Capabilities (\xepref{0115}) & \\
|
||||||
\hline \modconfigure{} & Server configuration using Ad-Hoc & \modadhoc{} \\
|
\hline \modconfigure{} & Server configuration using Ad-Hoc & \modadhoc{} \\
|
||||||
\hline \ahrefloc{moddisco}{\moddisco{}} & Service Discovery (\xepref{0030}) & \\
|
\hline \ahrefloc{moddisco}{\moddisco{}} & Service Discovery (\xepref{0030}) & \\
|
||||||
@ -2540,8 +2550,9 @@ The following table lists all modules included in \ejabberd{}.
|
|||||||
\hline \ahrefloc{modoffline}{\modoffline{}} & Offline message storage (\xepref{0160}) & \\
|
\hline \ahrefloc{modoffline}{\modoffline{}} & Offline message storage (\xepref{0160}) & \\
|
||||||
\hline \ahrefloc{modoffline}{\modofflineodbc{}} & Offline message storage (\xepref{0160}) & supported DB (*) \\
|
\hline \ahrefloc{modoffline}{\modofflineodbc{}} & Offline message storage (\xepref{0160}) & supported DB (*) \\
|
||||||
\hline \ahrefloc{modping}{\modping{}} & XMPP Ping and periodic keepalives (\xepref{0199}) & \\
|
\hline \ahrefloc{modping}{\modping{}} & XMPP Ping and periodic keepalives (\xepref{0199}) & \\
|
||||||
\hline \ahrefloc{modprivacy}{\modprivacy{}} & Blocking Communication (XMPP IM) & \\
|
\hline \ahrefloc{modprescounter}{\modprivacy{}} & Detect presence subscription flood & \\
|
||||||
\hline \ahrefloc{modprivacy}{\modprivacyodbc{}} & Blocking Communication (XMPP IM) & supported DB (*) \\
|
\hline \ahrefloc{modprivacy}{\modprivacy{}} & Blocking Communication (\xepref{0016}) & \\
|
||||||
|
\hline \ahrefloc{modprivacy}{\modprivacyodbc{}} & Blocking Communication (\xepref{0016}) & supported DB (*) \\
|
||||||
\hline \ahrefloc{modprivate}{\modprivate{}} & Private XML Storage (\xepref{0049}) & \\
|
\hline \ahrefloc{modprivate}{\modprivate{}} & Private XML Storage (\xepref{0049}) & \\
|
||||||
\hline \ahrefloc{modprivate}{\modprivateodbc{}} & Private XML Storage (\xepref{0049}) & supported DB (*) \\
|
\hline \ahrefloc{modprivate}{\modprivateodbc{}} & Private XML Storage (\xepref{0049}) & supported DB (*) \\
|
||||||
\hline \ahrefloc{modproxy}{\modproxy{}} & SOCKS5 Bytestreams (\xepref{0065}) & \\
|
\hline \ahrefloc{modproxy}{\modproxy{}} & SOCKS5 Bytestreams (\xepref{0065}) & \\
|
||||||
@ -2625,7 +2636,8 @@ The syntax is:
|
|||||||
Possible \term{Value} are:
|
Possible \term{Value} are:
|
||||||
\begin{description}
|
\begin{description}
|
||||||
\titem{no\_queue} All queries of a namespace with this processing discipline are
|
\titem{no\_queue} All queries of a namespace with this processing discipline are
|
||||||
processed immediately. This also means that no other packets can be processed
|
processed directly. This means that the XMPP connection that sends this IQ query gets blocked:
|
||||||
|
no other packets can be processed
|
||||||
until this one has been completely processed. Hence this discipline is not
|
until this one has been completely processed. Hence this discipline is not
|
||||||
recommended if the processing of a query can take a relatively long time.
|
recommended if the processing of a query can take a relatively long time.
|
||||||
\titem{one\_queue} In this case a separate queue is created for the processing
|
\titem{one\_queue} In this case a separate queue is created for the processing
|
||||||
@ -2633,7 +2645,7 @@ Possible \term{Value} are:
|
|||||||
of this queue is done in parallel with that of other packets. This discipline
|
of this queue is done in parallel with that of other packets. This discipline
|
||||||
is most recommended.
|
is most recommended.
|
||||||
\titem{\{queues, N\}} N separate queues are created to process the
|
\titem{\{queues, N\}} N separate queues are created to process the
|
||||||
queries. The queries are thus process in parallel, but in a
|
queries. The queries are thus processed in parallel, but in a
|
||||||
controlled way.
|
controlled way.
|
||||||
\titem{parallel} For every packet with this discipline a separate Erlang process
|
\titem{parallel} For every packet with this discipline a separate Erlang process
|
||||||
is spawned. Consequently, all these packets are processed in parallel.
|
is spawned. Consequently, all these packets are processed in parallel.
|
||||||
@ -3564,6 +3576,39 @@ and if a client does not answer to the ping in less than 32 seconds, its connect
|
|||||||
]}.
|
]}.
|
||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
|
|
||||||
|
\makesubsection{modprescounter}{\modprescounter{}}
|
||||||
|
\ind{modules!\modprescounter{}}
|
||||||
|
|
||||||
|
This module detects flood/spam in presence subscription stanza traffic.
|
||||||
|
If a user sends or receives more of those stanzas in a time interval,
|
||||||
|
the exceeding stanzas are silently dropped, and warning is logged.
|
||||||
|
|
||||||
|
Configuration options:
|
||||||
|
\begin{description}
|
||||||
|
\titem{\{count, StanzaNumber\}}\ind{options!count}
|
||||||
|
The number of subscription presence stanzas
|
||||||
|
(subscribe, unsubscribe, subscribed, unsubscribed)
|
||||||
|
allowed for any direction (input or output)
|
||||||
|
per time interval.
|
||||||
|
Please note that two users subscribing to each other usually generate
|
||||||
|
4 stanzas, so the recommended value is 4 or more.
|
||||||
|
The default value is: 5.
|
||||||
|
\titem{\{interval, Seconds\}}\ind{options!interval}
|
||||||
|
The time interval defined in seconds.
|
||||||
|
The default value is 60.
|
||||||
|
\end{description}
|
||||||
|
|
||||||
|
This example enables the module, and allows up to 5 presence subscription stanzas
|
||||||
|
to be sent or received by the users in 60 seconds:
|
||||||
|
\begin{verbatim}
|
||||||
|
{modules,
|
||||||
|
[
|
||||||
|
...
|
||||||
|
{mod_pres_counter, [{count, 5}, {interval, 60}]},
|
||||||
|
...
|
||||||
|
]}.
|
||||||
|
\end{verbatim}
|
||||||
|
|
||||||
\makesubsection{modprivacy}{\modprivacy{}}
|
\makesubsection{modprivacy}{\modprivacy{}}
|
||||||
\ind{modules!\modprivacy{}}\ind{Blocking Communication}\ind{Privacy Rules}\ind{protocols!RFC 3921: XMPP IM}
|
\ind{modules!\modprivacy{}}\ind{Blocking Communication}\ind{Privacy Rules}\ind{protocols!RFC 3921: XMPP IM}
|
||||||
|
|
||||||
@ -3788,10 +3833,11 @@ enables end users to use a \XMPP{} client to:
|
|||||||
|
|
||||||
Options:
|
Options:
|
||||||
\begin{description}
|
\begin{description}
|
||||||
\titem{\{access, AccessName\}} \ind{options!access}This option can be configured to specify
|
\titem{\{access, AccessName\}} \ind{options!access}
|
||||||
rules to restrict registration. If a rule returns `deny' on the requested
|
Specify rules to restrict what usernames can be registered and unregistered.
|
||||||
user name, registration for that user name is denied. (there are no
|
If a rule returns `deny' on the requested username,
|
||||||
restrictions by default).
|
registration and unregistration of that user name is denied.
|
||||||
|
There are no restrictions by default.
|
||||||
\titem{\{access\_from, AccessName\}} \ind{options!access\_from}By default, \ejabberd{}
|
\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
|
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
|
change it by defining access rule in this option. Use with care: allowing registration
|
||||||
@ -3808,7 +3854,7 @@ Protect registrations with CAPTCHA (see section \ref{captcha}). The default is \
|
|||||||
This option sets the minimum informational entropy for passwords. The value \term{Entropy}
|
This option sets the minimum informational entropy for passwords. The value \term{Entropy}
|
||||||
is a number of bits of entropy. The recommended minimum is 32 bits.
|
is a number of bits of entropy. The recommended minimum is 32 bits.
|
||||||
The default is 0, i.e. no checks are performed.
|
The default is 0, i.e. no checks are performed.
|
||||||
\titem{\{welcome\_message, Message\}} \ind{options!welcomem}Set a welcome message that
|
\titem{\{welcome\_message, \{Subject, Body\}\}} \ind{options!welcomem}Set a welcome message that
|
||||||
is sent to each newly registered account. The first string is the subject, and
|
is sent to each newly registered account. The first string is the subject, and
|
||||||
the second string is the message body.
|
the second string is the message body.
|
||||||
In the body you can set a newline with the characters: \verb|\n|
|
In the body you can set a newline with the characters: \verb|\n|
|
||||||
@ -4029,11 +4075,13 @@ has a unique identification and the following parameters:
|
|||||||
\item[Name] The name of the group, which will be displayed in the roster.
|
\item[Name] The name of the group, which will be displayed in the roster.
|
||||||
\item[Description] The description of the group. This parameter does not affect
|
\item[Description] The description of the group. This parameter does not affect
|
||||||
anything.
|
anything.
|
||||||
\item[Members] A list of full JIDs of group members, entered one per line in
|
\item[Members] A list of JIDs of group members, entered one per line in
|
||||||
the Web Admin.
|
the Web Admin.
|
||||||
To put as members all the registered users in the virtual hosts,
|
The special member directive \term{@all@}
|
||||||
you can use the special directive: @all@.
|
represents all the registered users in the virtual host;
|
||||||
Note that this directive is designed for a small server with just a few hundred users.
|
which is only recommended for a small server with just a few hundred users.
|
||||||
|
The special member directive \term{@online@}
|
||||||
|
represents the online users in the virtual host.
|
||||||
\item[Displayed groups] A list of groups that will be in the rosters of this
|
\item[Displayed groups] A list of groups that will be in the rosters of this
|
||||||
group's members.
|
group's members.
|
||||||
\end{description}
|
\end{description}
|
||||||
@ -4964,6 +5012,9 @@ The command line parameters:
|
|||||||
If using \term{-sname}, specify either this option or \term{ERL\_INETRC}.
|
If using \term{-sname}, specify either this option or \term{ERL\_INETRC}.
|
||||||
\titem{-kernel inet\_dist\_listen\_min 4200 inet\_dist\_listen\_min 4210}
|
\titem{-kernel inet\_dist\_listen\_min 4200 inet\_dist\_listen\_min 4210}
|
||||||
Define the first and last ports that \term{epmd} (section \ref{epmd}) can listen to.
|
Define the first and last ports that \term{epmd} (section \ref{epmd}) can listen to.
|
||||||
|
\titem{-kernel inet\_dist\_use\_interface "\{ 127,0,0,1 \}"}
|
||||||
|
Define the IP address where this Erlang node listens for other nodes
|
||||||
|
connections (see section \ref{epmd}).
|
||||||
\titem{-detached}
|
\titem{-detached}
|
||||||
Starts the Erlang system detached from the system console.
|
Starts the Erlang system detached from the system console.
|
||||||
Useful for running daemons and backgrounds processes.
|
Useful for running daemons and backgrounds processes.
|
||||||
@ -5376,6 +5427,12 @@ The Erlang command-line parameter used internally is, for example:
|
|||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
erl ... -kernel inet_dist_listen_min 4370 inet_dist_listen_max 4375
|
erl ... -kernel inet_dist_listen_min 4370 inet_dist_listen_max 4375
|
||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
|
It is also possible to configure in \term{ejabberdctl.cfg}
|
||||||
|
the network interface where the Erlang node will listen and accept connections.
|
||||||
|
The Erlang command-line parameter used internally is, for example:
|
||||||
|
\begin{verbatim}
|
||||||
|
erl ... -kernel inet_dist_use_interface "{127,0,0,1}"
|
||||||
|
\end{verbatim}
|
||||||
|
|
||||||
|
|
||||||
\makesection{cookie}{Erlang Cookie}
|
\makesection{cookie}{Erlang Cookie}
|
||||||
|
@ -213,6 +213,7 @@ install: all
|
|||||||
sed -e "s*@ctlscriptpath@*$(SBINDIR)*" \
|
sed -e "s*@ctlscriptpath@*$(SBINDIR)*" \
|
||||||
-e "s*@installuser@*$(INIT_USER)*" ejabberd.init.template \
|
-e "s*@installuser@*$(INIT_USER)*" ejabberd.init.template \
|
||||||
> ejabberd.init
|
> ejabberd.init
|
||||||
|
chmod 755 ejabberd.init
|
||||||
#
|
#
|
||||||
# Binary Erlang files
|
# Binary Erlang files
|
||||||
install -d $(BEAMDIR)
|
install -d $(BEAMDIR)
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 18 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 18 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 31 Oct 2005 by Magnus Henoch <henoch@dtek.chalmers.se>
|
%%% Created : 31 Oct 2005 by Magnus Henoch <henoch@dtek.chalmers.se>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
%%% Created : 29 Aug 2010 by Evgeniy Khramtsov <ekhramtsov@process-one.net>
|
%%% Created : 29 Aug 2010 by Evgeniy Khramtsov <ekhramtsov@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
%%% Created : 30 Aug 2010 by Evgeniy Khramtsov <ekhramtsov@process-one.net>
|
%%% Created : 30 Aug 2010 by Evgeniy Khramtsov <ekhramtsov@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 27 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 27 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 8 Mar 2003 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 8 Mar 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% 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>
|
%%% Created : 23 Aug 2005 by Magnus Henoch <henoch@dtek.chalmers.se>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% 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>
|
%%% Created : 11 Mar 2003 by Alexey Shchepin <alexey@sevcom.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 8 Mar 2003 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 8 Mar 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -475,10 +475,14 @@
|
|||||||
%%{captcha_cmd, "/lib/ejabberd/priv/bin/captcha.sh"}.
|
%%{captcha_cmd, "/lib/ejabberd/priv/bin/captcha.sh"}.
|
||||||
|
|
||||||
%%
|
%%
|
||||||
%% Host part of the URL sent to the user.
|
%% Host for the URL and port where ejabberd listens for CAPTCHA requests.
|
||||||
%%
|
%%
|
||||||
%%{captcha_host, "example.org:5280"}.
|
%%{captcha_host, "example.org:5280"}.
|
||||||
|
|
||||||
|
%%
|
||||||
|
%% Limit CAPTCHA calls per minute for JID/IP to avoid DoS.
|
||||||
|
%%
|
||||||
|
%%{captcha_limit, 5}.
|
||||||
|
|
||||||
%%%. =======
|
%%%. =======
|
||||||
%%%' MODULES
|
%%%' MODULES
|
||||||
@ -490,6 +494,7 @@
|
|||||||
[
|
[
|
||||||
{mod_adhoc, []},
|
{mod_adhoc, []},
|
||||||
{mod_announce, [{access, announce}]}, % recommends mod_adhoc
|
{mod_announce, [{access, announce}]}, % recommends mod_adhoc
|
||||||
|
{mod_blocking,[]}, % requires mod_privacy
|
||||||
{mod_caps, []},
|
{mod_caps, []},
|
||||||
{mod_configure,[]}, % requires mod_adhoc
|
{mod_configure,[]}, % requires mod_adhoc
|
||||||
{mod_disco, []},
|
{mod_disco, []},
|
||||||
@ -511,6 +516,7 @@
|
|||||||
%%{mod_muc_log,[]},
|
%%{mod_muc_log,[]},
|
||||||
{mod_offline, [{access_max_user_messages, max_user_offline_messages}]},
|
{mod_offline, [{access_max_user_messages, max_user_offline_messages}]},
|
||||||
{mod_ping, []},
|
{mod_ping, []},
|
||||||
|
%%{mod_pres_counter,[{count, 5}, {interval, 60}]},
|
||||||
{mod_privacy, []},
|
{mod_privacy, []},
|
||||||
{mod_private, []},
|
{mod_private, []},
|
||||||
%%{mod_proxy65,[]},
|
%%{mod_proxy65,[]},
|
||||||
@ -545,9 +551,17 @@
|
|||||||
%%
|
%%
|
||||||
%%{registration_watchers, ["admin1@example.org"]},
|
%%{registration_watchers, ["admin1@example.org"]},
|
||||||
|
|
||||||
|
%%
|
||||||
|
%% Only clients in the server machine can register accounts
|
||||||
|
%%
|
||||||
{ip_access, [{allow, "127.0.0.0/8"},
|
{ip_access, [{allow, "127.0.0.0/8"},
|
||||||
{deny, "0.0.0.0/0"}]},
|
{deny, "0.0.0.0/0"}]},
|
||||||
|
|
||||||
|
%%
|
||||||
|
%% Local c2s or remote s2s users cannot register accounts
|
||||||
|
%%
|
||||||
|
%%{access_from, deny},
|
||||||
|
|
||||||
{access, register}
|
{access, register}
|
||||||
]},
|
]},
|
||||||
%%{mod_register_web, [
|
%%{mod_register_web, [
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 16 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 16 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -1,6 +1,20 @@
|
|||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
|
|
||||||
|
### BEGIN INIT INFO
|
||||||
|
# Provides: ejabberd
|
||||||
|
# Required-Start: $remote_fs $network $named $time
|
||||||
|
# Required-Stop: $remote_fs $network $named $time
|
||||||
|
# Default-Start: 2 3 4 5
|
||||||
|
# Default-Stop: 0 1 6
|
||||||
|
# Short-Description: Starts ejabberd jabber server
|
||||||
|
# Description: Starts ejabberd jabber server, an XMPP
|
||||||
|
# compliant server written in Erlang.
|
||||||
|
### END INIT INFO
|
||||||
|
|
||||||
|
# chkconfig: 2345 90 10
|
||||||
|
# description: ejabberd XMPP server
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o nounset
|
|
||||||
|
|
||||||
DIR=@ctlscriptpath@
|
DIR=@ctlscriptpath@
|
||||||
CTL="$DIR"/ejabberdctl
|
CTL="$DIR"/ejabberdctl
|
||||||
@ -32,14 +46,17 @@ case "$1" in
|
|||||||
su - $USER -c "$CTL stopped"
|
su - $USER -c "$CTL stopped"
|
||||||
echo "done."
|
echo "done."
|
||||||
;;
|
;;
|
||||||
|
status)
|
||||||
|
test -x "$CTL" || exit 0
|
||||||
|
echo "Getting ejabberd status..."
|
||||||
|
su - $USER -c "$CTL status"
|
||||||
|
;;
|
||||||
force-reload|restart)
|
force-reload|restart)
|
||||||
"$0" stop
|
"$0" stop
|
||||||
"$0" start
|
"$0" start
|
||||||
;;
|
;;
|
||||||
|
|
||||||
*)
|
*)
|
||||||
echo "Usage: $0 {start|stop|restart|force-reload}"
|
echo "Usage: $0 {start|stop|restart|force-reload|status}"
|
||||||
exit 1
|
exit 1
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 7 May 2006 by Mickael Remond <mremond@process-one.net>
|
%%% Created : 7 May 2006 by Mickael Remond <mremond@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% 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>
|
%%% Created : 31 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
@ -67,8 +67,9 @@ start(normal, _Args) ->
|
|||||||
%ejabberd_debug:eprof_start(),
|
%ejabberd_debug:eprof_start(),
|
||||||
%ejabberd_debug:fprof_start(),
|
%ejabberd_debug:fprof_start(),
|
||||||
maybe_add_nameservers(),
|
maybe_add_nameservers(),
|
||||||
|
{ok, Pid} = ejabberd_cluster:start(),
|
||||||
start_modules(),
|
start_modules(),
|
||||||
ejabberd_cluster:announce(),
|
ejabberd_cluster:announce(Pid),
|
||||||
ejabberd_node_groups:start(),
|
ejabberd_node_groups:start(),
|
||||||
ejabberd_listener:start_listeners(),
|
ejabberd_listener:start_listeners(),
|
||||||
?INFO_MSG("ejabberd ~s is started in the node ~p", [?VERSION, node()]),
|
?INFO_MSG("ejabberd ~s is started in the node ~p", [?VERSION, node()]),
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 23 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 23 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 17 Feb 2006 by Mickael Remond <mremond@process-one.net>
|
%%% Created : 17 Feb 2006 by Mickael Remond <mremond@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
@ -155,6 +155,7 @@ register_connection(SID, #jid{luser = LUser, lserver = LServer}, Info) ->
|
|||||||
AuthModule = xml:get_attr_s(auth_module, Info),
|
AuthModule = xml:get_attr_s(auth_module, Info),
|
||||||
case AuthModule == ?MODULE of
|
case AuthModule == ?MODULE of
|
||||||
true ->
|
true ->
|
||||||
|
ejabberd_hooks:run(register_user, LServer, [LUser, LServer]),
|
||||||
US = {LUser, LServer},
|
US = {LUser, LServer},
|
||||||
mnesia:async_dirty(
|
mnesia:async_dirty(
|
||||||
fun() -> mnesia:write(#anonymous{us = US, sid=SID})
|
fun() -> mnesia:write(#anonymous{us = US, sid=SID})
|
||||||
@ -231,8 +232,8 @@ try_register(_User, _Server, _Password) ->
|
|||||||
dirty_get_registered_users() ->
|
dirty_get_registered_users() ->
|
||||||
[].
|
[].
|
||||||
|
|
||||||
get_vh_registered_users(_Server) ->
|
get_vh_registered_users(Server) ->
|
||||||
[].
|
[{U, S} || {U, S, _R} <- ejabberd_sm:get_vh_session_list(Server)].
|
||||||
|
|
||||||
|
|
||||||
%% Return password of permanent user or false for anonymous users
|
%% Return password of permanent user or false for anonymous users
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% 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>
|
%%% Created : 5 Jul 2007 by Evgeniy Khramtsov <xram@jabber.ru>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% 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>
|
%%% Created : 16 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
@ -194,7 +194,7 @@ stop(FsmRef) ->
|
|||||||
?GEN_FSM:send_event(FsmRef, closed).
|
?GEN_FSM:send_event(FsmRef, closed).
|
||||||
|
|
||||||
migrate(FsmRef, Node, After) ->
|
migrate(FsmRef, Node, After) ->
|
||||||
?GEN_FSM:send_all_state_event(FsmRef, {migrate, Node, After}).
|
erlang:send_after(After, FsmRef, {migrate, Node}).
|
||||||
|
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
%%% Callback functions from gen_fsm
|
%%% Callback functions from gen_fsm
|
||||||
@ -231,6 +231,12 @@ init([{SockMod, Socket}, Opts, FSMLimitOpts]) ->
|
|||||||
(_) -> false
|
(_) -> false
|
||||||
end, Opts),
|
end, Opts),
|
||||||
TLSOpts = [verify_none | TLSOpts1],
|
TLSOpts = [verify_none | TLSOpts1],
|
||||||
|
Redirect = case lists:keysearch(redirect, 1, Opts) of
|
||||||
|
{value, {_, true}} ->
|
||||||
|
true;
|
||||||
|
_ ->
|
||||||
|
false
|
||||||
|
end,
|
||||||
IP = case lists:keysearch(frontend_ip, 1, Opts) of
|
IP = case lists:keysearch(frontend_ip, 1, Opts) of
|
||||||
{value, {_, IP1}} ->
|
{value, {_, IP1}} ->
|
||||||
IP1;
|
IP1;
|
||||||
@ -246,7 +252,7 @@ init([{SockMod, Socket}, Opts, FSMLimitOpts]) ->
|
|||||||
false ->
|
false ->
|
||||||
Socket1 =
|
Socket1 =
|
||||||
if
|
if
|
||||||
TLSEnabled ->
|
TLSEnabled andalso SockMod /= ejabberd_frontend_socket ->
|
||||||
SockMod:starttls(Socket, TLSOpts);
|
SockMod:starttls(Socket, TLSOpts);
|
||||||
true ->
|
true ->
|
||||||
Socket
|
Socket
|
||||||
@ -265,8 +271,20 @@ init([{SockMod, Socket}, Opts, FSMLimitOpts]) ->
|
|||||||
access = Access,
|
access = Access,
|
||||||
shaper = Shaper,
|
shaper = Shaper,
|
||||||
ip = IP,
|
ip = IP,
|
||||||
|
redirect = Redirect,
|
||||||
fsm_limit_opts = FSMLimitOpts},
|
fsm_limit_opts = FSMLimitOpts},
|
||||||
|
case get_jid_from_opts(Opts) of
|
||||||
|
{ok, #jid{user = U, server = Server, resource = R} = JID} ->
|
||||||
|
?GEN_FSM:send_event(self(), open_session),
|
||||||
|
{ok, wait_for_session, StateData#state{
|
||||||
|
user = U,
|
||||||
|
server = Server,
|
||||||
|
resource = R,
|
||||||
|
jid = JID,
|
||||||
|
lang = ""}};
|
||||||
|
_ ->
|
||||||
{ok, wait_for_stream, StateData, ?C2S_OPEN_TIMEOUT}
|
{ok, wait_for_stream, StateData, ?C2S_OPEN_TIMEOUT}
|
||||||
|
end
|
||||||
end;
|
end;
|
||||||
init([StateName, StateData, _FSMLimitOpts]) ->
|
init([StateName, StateData, _FSMLimitOpts]) ->
|
||||||
MRef = (StateData#state.sockmod):monitor(StateData#state.socket),
|
MRef = (StateData#state.sockmod):monitor(StateData#state.socket),
|
||||||
@ -282,6 +300,7 @@ init([StateName, StateData, _FSMLimitOpts]) ->
|
|||||||
El ->
|
El ->
|
||||||
get_priority_from_presence(El)
|
get_priority_from_presence(El)
|
||||||
end,
|
end,
|
||||||
|
ejabberd_sm:drop_session(StateData#state.sid),
|
||||||
ejabberd_sm:open_session(
|
ejabberd_sm:open_session(
|
||||||
SID,
|
SID,
|
||||||
StateData#state.user,
|
StateData#state.user,
|
||||||
@ -289,8 +308,11 @@ init([StateName, StateData, _FSMLimitOpts]) ->
|
|||||||
StateData#state.resource,
|
StateData#state.resource,
|
||||||
Priority,
|
Priority,
|
||||||
Info),
|
Info),
|
||||||
|
%%ejabberd_sm:drop_session(StateData#state.sid),
|
||||||
NewStateData = StateData#state{sid = SID, socket_monitor = MRef},
|
NewStateData = StateData#state{sid = SID, socket_monitor = MRef},
|
||||||
{ok, StateName, NewStateData};
|
StateData2 = change_reception(NewStateData, true),
|
||||||
|
StateData3 = start_keepalive_timer(StateData2),
|
||||||
|
{ok, StateName, StateData3};
|
||||||
true ->
|
true ->
|
||||||
{ok, StateName, StateData#state{socket_monitor = MRef}}
|
{ok, StateName, StateData#state{socket_monitor = MRef}}
|
||||||
end.
|
end.
|
||||||
@ -581,15 +603,20 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
|
|||||||
"(~w) Accepted legacy authentication for ~s by ~p",
|
"(~w) Accepted legacy authentication for ~s by ~p",
|
||||||
[StateData#state.socket,
|
[StateData#state.socket,
|
||||||
jlib:jid_to_string(JID), AuthModule]),
|
jlib:jid_to_string(JID), AuthModule]),
|
||||||
|
case need_redirect(StateData#state{user = U}) of
|
||||||
|
{true, Host} ->
|
||||||
|
?INFO_MSG("(~w) Redirecting ~s to ~s",
|
||||||
|
[StateData#state.socket,
|
||||||
|
jlib:jid_to_string(JID), Host]),
|
||||||
|
send_element(StateData, ?SERR_SEE_OTHER_HOST(Host)),
|
||||||
|
send_trailer(StateData),
|
||||||
|
{stop, normal, StateData};
|
||||||
|
false ->
|
||||||
SID = {now(), self()},
|
SID = {now(), self()},
|
||||||
Conn = get_conn_type(StateData),
|
Conn = get_conn_type(StateData),
|
||||||
%% Info = [{ip, StateData#state.ip}, {conn, Conn},
|
|
||||||
%% {auth_module, AuthModule}],
|
|
||||||
Res1 = jlib:make_result_iq_reply(El),
|
Res1 = jlib:make_result_iq_reply(El),
|
||||||
Res = setelement(4, Res1, []),
|
Res = setelement(4, Res1, []),
|
||||||
send_element(StateData, Res),
|
send_element(StateData, Res),
|
||||||
%% ejabberd_sm:open_session(
|
|
||||||
%% SID, U, StateData#state.server, R, Info),
|
|
||||||
change_shaper(StateData, JID),
|
change_shaper(StateData, JID),
|
||||||
{Fs, Ts} = ejabberd_hooks:run_fold(
|
{Fs, Ts} = ejabberd_hooks:run_fold(
|
||||||
roster_get_subscription_lists,
|
roster_get_subscription_lists,
|
||||||
@ -602,10 +629,12 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
|
|||||||
Ts1 = [LJID | Ts],
|
Ts1 = [LJID | Ts],
|
||||||
PrivList =
|
PrivList =
|
||||||
ejabberd_hooks:run_fold(
|
ejabberd_hooks:run_fold(
|
||||||
privacy_get_user_list, StateData#state.server,
|
privacy_get_user_list,
|
||||||
|
StateData#state.server,
|
||||||
#userlist{},
|
#userlist{},
|
||||||
[U, StateData#state.server]),
|
[U, StateData#state.server]),
|
||||||
NewStateData = StateData#state{
|
NewStateData =
|
||||||
|
StateData#state{
|
||||||
user = U,
|
user = U,
|
||||||
resource = R,
|
resource = R,
|
||||||
jid = JID,
|
jid = JID,
|
||||||
@ -615,11 +644,14 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
|
|||||||
pres_f = ?SETS:from_list(Fs1),
|
pres_f = ?SETS:from_list(Fs1),
|
||||||
pres_t = ?SETS:from_list(Ts1),
|
pres_t = ?SETS:from_list(Ts1),
|
||||||
privacy_list = PrivList},
|
privacy_list = PrivList},
|
||||||
DebugFlag = ejabberd_hooks:run_fold(c2s_debug_start_hook,
|
DebugFlag = ejabberd_hooks:run_fold(
|
||||||
|
c2s_debug_start_hook,
|
||||||
NewStateData#state.server,
|
NewStateData#state.server,
|
||||||
false,
|
false,
|
||||||
[self(), NewStateData]),
|
[self(), NewStateData]),
|
||||||
maybe_migrate(session_established, NewStateData#state{debug=DebugFlag});
|
maybe_migrate(session_established,
|
||||||
|
NewStateData#state{debug=DebugFlag})
|
||||||
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
?INFO_MSG(
|
?INFO_MSG(
|
||||||
"(~w) Failed legacy authentication for ~s",
|
"(~w) Failed legacy authentication for ~s",
|
||||||
@ -713,19 +745,28 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) ->
|
|||||||
{ok, Props} ->
|
{ok, Props} ->
|
||||||
catch (StateData#state.sockmod):reset_stream(
|
catch (StateData#state.sockmod):reset_stream(
|
||||||
StateData#state.socket),
|
StateData#state.socket),
|
||||||
send_element(StateData,
|
|
||||||
{xmlelement, "success",
|
|
||||||
[{"xmlns", ?NS_SASL}], []}),
|
|
||||||
U = xml:get_attr_s(username, Props),
|
U = xml:get_attr_s(username, Props),
|
||||||
AuthModule = xml:get_attr_s(auth_module, Props),
|
AuthModule = xml:get_attr_s(auth_module, Props),
|
||||||
?INFO_MSG("(~w) Accepted authentication for ~s by ~p",
|
?INFO_MSG("(~w) Accepted authentication for ~s by ~p",
|
||||||
[StateData#state.socket, U, AuthModule]),
|
[StateData#state.socket, U, AuthModule]),
|
||||||
|
case need_redirect(StateData#state{user = U}) of
|
||||||
|
{true, Host} ->
|
||||||
|
?INFO_MSG("(~w) Redirecting ~s to ~s",
|
||||||
|
[StateData#state.socket, U, Host]),
|
||||||
|
send_element(StateData, ?SERR_SEE_OTHER_HOST(Host)),
|
||||||
|
send_trailer(StateData),
|
||||||
|
{stop, normal, StateData};
|
||||||
|
false ->
|
||||||
|
send_element(StateData,
|
||||||
|
{xmlelement, "success",
|
||||||
|
[{"xmlns", ?NS_SASL}], []}),
|
||||||
fsm_next_state(wait_for_stream,
|
fsm_next_state(wait_for_stream,
|
||||||
StateData#state{
|
StateData#state{
|
||||||
streamid = new_id(),
|
streamid = new_id(),
|
||||||
authenticated = true,
|
authenticated = true,
|
||||||
auth_module = AuthModule,
|
auth_module = AuthModule,
|
||||||
user = U });
|
user = U })
|
||||||
|
end;
|
||||||
{continue, ServerOut, NewSASLState} ->
|
{continue, ServerOut, NewSASLState} ->
|
||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
{xmlelement, "challenge",
|
{xmlelement, "challenge",
|
||||||
@ -866,19 +907,28 @@ wait_for_sasl_response({xmlstreamelement, El}, StateData) ->
|
|||||||
{ok, Props} ->
|
{ok, Props} ->
|
||||||
catch (StateData#state.sockmod):reset_stream(
|
catch (StateData#state.sockmod):reset_stream(
|
||||||
StateData#state.socket),
|
StateData#state.socket),
|
||||||
send_element(StateData,
|
|
||||||
{xmlelement, "success",
|
|
||||||
[{"xmlns", ?NS_SASL}], []}),
|
|
||||||
U = xml:get_attr_s(username, Props),
|
U = xml:get_attr_s(username, Props),
|
||||||
AuthModule = xml:get_attr_s(auth_module, Props),
|
AuthModule = xml:get_attr_s(auth_module, Props),
|
||||||
?INFO_MSG("(~w) Accepted authentication for ~s by ~p",
|
?INFO_MSG("(~w) Accepted authentication for ~s by ~p",
|
||||||
[StateData#state.socket, U, AuthModule]),
|
[StateData#state.socket, U, AuthModule]),
|
||||||
|
case need_redirect(StateData#state{user = U}) of
|
||||||
|
{true, Host} ->
|
||||||
|
?INFO_MSG("(~w) Redirecting ~s to ~s",
|
||||||
|
[StateData#state.socket, U, Host]),
|
||||||
|
send_element(StateData, ?SERR_SEE_OTHER_HOST(Host)),
|
||||||
|
send_trailer(StateData),
|
||||||
|
{stop, normal, StateData};
|
||||||
|
false ->
|
||||||
|
send_element(StateData,
|
||||||
|
{xmlelement, "success",
|
||||||
|
[{"xmlns", ?NS_SASL}], []}),
|
||||||
fsm_next_state(wait_for_stream,
|
fsm_next_state(wait_for_stream,
|
||||||
StateData#state{
|
StateData#state{
|
||||||
streamid = new_id(),
|
streamid = new_id(),
|
||||||
authenticated = true,
|
authenticated = true,
|
||||||
auth_module = AuthModule,
|
auth_module = AuthModule,
|
||||||
user = U});
|
user = U})
|
||||||
|
end;
|
||||||
{continue, ServerOut, NewSASLState} ->
|
{continue, ServerOut, NewSASLState} ->
|
||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
{xmlelement, "challenge",
|
{xmlelement, "challenge",
|
||||||
@ -1045,6 +1095,11 @@ wait_for_session({xmlstreamelement, El}, StateData) ->
|
|||||||
fsm_next_state(wait_for_session, StateData)
|
fsm_next_state(wait_for_session, StateData)
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
wait_for_session(open_session, StateData) ->
|
||||||
|
El = {xmlelement, "iq", [{"type", "set"}, {"id", "session"}],
|
||||||
|
[{xmlelement, "session", [{"xmlns", ?NS_SESSION}], []}]},
|
||||||
|
wait_for_session({xmlstreamelement, El}, StateData);
|
||||||
|
|
||||||
wait_for_session(timeout, StateData) ->
|
wait_for_session(timeout, StateData) ->
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
@ -1172,7 +1227,9 @@ session_established2(El, StateData) ->
|
|||||||
end;
|
end;
|
||||||
"iq" ->
|
"iq" ->
|
||||||
case jlib:iq_query_info(NewEl) of
|
case jlib:iq_query_info(NewEl) of
|
||||||
#iq{xmlns = ?NS_PRIVACY} = IQ ->
|
#iq{xmlns = Xmlns} = IQ
|
||||||
|
when Xmlns == ?NS_PRIVACY;
|
||||||
|
Xmlns == ?NS_BLOCKING ->
|
||||||
ejabberd_hooks:run(
|
ejabberd_hooks:run(
|
||||||
user_send_packet,
|
user_send_packet,
|
||||||
Server,
|
Server,
|
||||||
@ -1230,9 +1287,6 @@ session_established2(El, StateData) ->
|
|||||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
%% {next_state, NextStateName, NextStateData, Timeout} |
|
||||||
%% {stop, Reason, NewStateData}
|
%% {stop, Reason, NewStateData}
|
||||||
%%----------------------------------------------------------------------
|
%%----------------------------------------------------------------------
|
||||||
handle_event({migrate, Node, After}, StateName, StateData) when Node /= node() ->
|
|
||||||
fsm_migrate(StateName, StateData, Node, After * 2);
|
|
||||||
|
|
||||||
handle_event({add_rosteritem, IJID, ISubscription}, StateName, StateData) ->
|
handle_event({add_rosteritem, IJID, ISubscription}, StateName, StateData) ->
|
||||||
NewStateData = roster_change(IJID, ISubscription, StateData),
|
NewStateData = roster_change(IJID, ISubscription, StateData),
|
||||||
fsm_next_state(StateName, NewStateData);
|
fsm_next_state(StateName, NewStateData);
|
||||||
@ -1433,6 +1487,9 @@ handle_info({route, From, To, Packet}, StateName, StateData) ->
|
|||||||
send_element(StateData, PrivPushEl),
|
send_element(StateData, PrivPushEl),
|
||||||
{false, Attrs, StateData#state{privacy_list = NewPL}}
|
{false, Attrs, StateData#state{privacy_list = NewPL}}
|
||||||
end;
|
end;
|
||||||
|
[{blocking, What}] ->
|
||||||
|
route_blocking(What, StateData),
|
||||||
|
{false, Attrs, StateData};
|
||||||
_ ->
|
_ ->
|
||||||
{false, Attrs, StateData}
|
{false, Attrs, StateData}
|
||||||
end;
|
end;
|
||||||
@ -1622,6 +1679,12 @@ handle_info({force_update_presence, LUser}, StateName,
|
|||||||
StateData
|
StateData
|
||||||
end,
|
end,
|
||||||
{next_state, StateName, NewStateData};
|
{next_state, StateName, NewStateData};
|
||||||
|
handle_info({migrate, Node}, StateName, StateData) ->
|
||||||
|
if Node /= node() ->
|
||||||
|
fsm_migrate(StateName, StateData, Node, 0);
|
||||||
|
true ->
|
||||||
|
fsm_next_state(StateName, StateData)
|
||||||
|
end;
|
||||||
handle_info({broadcast, Type, From, Packet}, StateName, StateData) ->
|
handle_info({broadcast, Type, From, Packet}, StateName, StateData) ->
|
||||||
Recipients = ejabberd_hooks:run_fold(
|
Recipients = ejabberd_hooks:run_fold(
|
||||||
c2s_broadcast_recipients, StateData#state.server,
|
c2s_broadcast_recipients, StateData#state.server,
|
||||||
@ -1698,7 +1761,7 @@ terminate(_Reason, StateName, StateData) ->
|
|||||||
presence_broadcast(
|
presence_broadcast(
|
||||||
StateData, From, StateData#state.pres_i, Packet);
|
StateData, From, StateData#state.pres_i, Packet);
|
||||||
rebinded ->
|
rebinded ->
|
||||||
ejabberd_sm:close_session(
|
ejabberd_sm:close_migrated_session(
|
||||||
StateData#state.sid,
|
StateData#state.sid,
|
||||||
StateData#state.user,
|
StateData#state.user,
|
||||||
StateData#state.server,
|
StateData#state.server,
|
||||||
@ -1969,24 +2032,12 @@ process_presence_probe(From, To, StateData) ->
|
|||||||
(E) ->
|
(E) ->
|
||||||
[E]
|
[E]
|
||||||
end, PresEls),
|
end, PresEls),
|
||||||
{xmlelement, "presence", PresAttrs,
|
make_oor_presence(
|
||||||
[{xmlelement, "show", [],
|
StateData, PresAttrs, PresEls1)
|
||||||
[{xmlcdata,
|
|
||||||
StateData#state.oor_show}]},
|
|
||||||
{xmlelement, "status", [],
|
|
||||||
[{xmlcdata,
|
|
||||||
StateData#state.oor_status}]}]
|
|
||||||
++ PresEls1}
|
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
Timestamp = StateData#state.pres_timestamp,
|
Timestamp = StateData#state.pres_timestamp,
|
||||||
Packet1 = xml:append_subtags(
|
Packet1 = maybe_add_delay(Packet, utc, To, "", Timestamp),
|
||||||
xml:remove_subtags(
|
|
||||||
Packet, "x", {"xmlns", ?NS_DELAY91}),
|
|
||||||
%% To is the one sending the presence (the target of the probe)
|
|
||||||
[jlib:timestamp_to_xml(Timestamp, utc, To, ""),
|
|
||||||
%% TODO: Delete the next line once XEP-0091 is Obsolete
|
|
||||||
jlib:timestamp_to_xml(Timestamp)]),
|
|
||||||
case ejabberd_hooks:run_fold(
|
case ejabberd_hooks:run_fold(
|
||||||
privacy_check_packet, StateData#state.server,
|
privacy_check_packet, StateData#state.server,
|
||||||
allow,
|
allow,
|
||||||
@ -2422,7 +2473,7 @@ resend_offline_messages(StateData) ->
|
|||||||
Rs when is_list(Rs) ->
|
Rs when is_list(Rs) ->
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun({route,
|
fun({route,
|
||||||
From, To, {xmlelement, Name, Attrs, Els} = Packet}) ->
|
From, To, {xmlelement, _Name, _Attrs, _Els} = Packet}) ->
|
||||||
Pass = case privacy_check_packet(StateData, From, To, Packet, in) of
|
Pass = case privacy_check_packet(StateData, From, To, Packet, in) of
|
||||||
allow ->
|
allow ->
|
||||||
true;
|
true;
|
||||||
@ -2431,11 +2482,11 @@ resend_offline_messages(StateData) ->
|
|||||||
end,
|
end,
|
||||||
if
|
if
|
||||||
Pass ->
|
Pass ->
|
||||||
Attrs2 = jlib:replace_from_to_attrs(
|
%% Attrs2 = jlib:replace_from_to_attrs(
|
||||||
jlib:jid_to_string(From),
|
%% jlib:jid_to_string(From),
|
||||||
jlib:jid_to_string(To),
|
%% jlib:jid_to_string(To),
|
||||||
Attrs),
|
%% Attrs),
|
||||||
FixedPacket = {xmlelement, Name, Attrs2, Els},
|
%% FixedPacket = {xmlelement, Name, Attrs2, Els},
|
||||||
%% Use route instead of send_element to go through standard workflow
|
%% Use route instead of send_element to go through standard workflow
|
||||||
ejabberd_router:route(From, To, Packet);
|
ejabberd_router:route(From, To, Packet);
|
||||||
%% send_element(StateData, FixedPacket),
|
%% send_element(StateData, FixedPacket),
|
||||||
@ -2526,23 +2577,25 @@ peerip(SockMod, Socket) ->
|
|||||||
|
|
||||||
maybe_migrate(StateName, StateData) ->
|
maybe_migrate(StateName, StateData) ->
|
||||||
PackedStateData = pack(StateData),
|
PackedStateData = pack(StateData),
|
||||||
case ejabberd_cluster:get_node({StateData#state.user,
|
#state{user = U, server = S, resource = R, sid = SID} = StateData,
|
||||||
StateData#state.server}) of
|
case ejabberd_cluster:get_node({jlib:nodeprep(U), jlib:nameprep(S)}) of
|
||||||
Node when Node == node() ->
|
Node when Node == node() ->
|
||||||
Conn = get_conn_type(StateData),
|
Conn = get_conn_type(StateData),
|
||||||
Info = [{ip, StateData#state.ip}, {conn, Conn},
|
Info = [{ip, StateData#state.ip}, {conn, Conn},
|
||||||
{auth_module, StateData#state.auth_module}],
|
{auth_module, StateData#state.auth_module}],
|
||||||
#state{user = U, server = S, resource = R, sid = SID} = StateData,
|
Presence = StateData#state.pres_last,
|
||||||
ejabberd_sm:open_session(SID, U, S, R, Info),
|
Priority =
|
||||||
erlang:garbage_collect(),
|
case Presence of
|
||||||
case ejabberd_cluster:get_node_new({U, S}) of
|
undefined ->
|
||||||
Node ->
|
undefined;
|
||||||
ok;
|
_ ->
|
||||||
NewNode ->
|
get_priority_from_presence(Presence)
|
||||||
After = ejabberd_cluster:rehash_timeout(),
|
|
||||||
migrate(self(), NewNode, After)
|
|
||||||
end,
|
end,
|
||||||
fsm_next_state(StateName, PackedStateData);
|
ejabberd_sm:open_session(SID, U, S, R, Priority, Info),
|
||||||
|
StateData2 = change_reception(PackedStateData, true),
|
||||||
|
StateData3 = start_keepalive_timer(StateData2),
|
||||||
|
erlang:garbage_collect(),
|
||||||
|
fsm_next_state(StateName, StateData3);
|
||||||
Node ->
|
Node ->
|
||||||
fsm_migrate(StateName, PackedStateData, Node, 0)
|
fsm_migrate(StateName, PackedStateData, Node, 0)
|
||||||
end.
|
end.
|
||||||
@ -2627,12 +2680,7 @@ change_reception(#state{reception = true} = StateData, false) ->
|
|||||||
"" ->
|
"" ->
|
||||||
ok;
|
ok;
|
||||||
_ ->
|
_ ->
|
||||||
Packet =
|
Packet = make_oor_presence(StateData),
|
||||||
{xmlelement, "presence", [],
|
|
||||||
[{xmlelement, "show", [],
|
|
||||||
[{xmlcdata, StateData#state.oor_show}]},
|
|
||||||
{xmlelement, "status", [],
|
|
||||||
[{xmlcdata, StateData#state.oor_status}]}]},
|
|
||||||
update_priority(0, Packet, StateData#state{reception = false}),
|
update_priority(0, Packet, StateData#state{reception = false}),
|
||||||
presence_broadcast_to_trusted(
|
presence_broadcast_to_trusted(
|
||||||
StateData,
|
StateData,
|
||||||
@ -2775,7 +2823,14 @@ send_out_of_reception_message(StateData, From, To,
|
|||||||
CBody = utf8_cut(Body, 100),
|
CBody = utf8_cut(Body, 100),
|
||||||
case StateData#state.oor_send_from of
|
case StateData#state.oor_send_from of
|
||||||
jid -> SFrom ++ ": " ++ CBody;
|
jid -> SFrom ++ ": " ++ CBody;
|
||||||
username -> BFrom#jid.user ++ ": " ++ CBody;
|
username ->
|
||||||
|
UnescapedFrom =
|
||||||
|
unescape(BFrom#jid.user),
|
||||||
|
UnescapedFrom ++ ": " ++ CBody;
|
||||||
|
name ->
|
||||||
|
Name = get_roster_name(
|
||||||
|
StateData, BFrom),
|
||||||
|
Name ++ ": " ++ CBody;
|
||||||
_ -> CBody
|
_ -> CBody
|
||||||
end;
|
end;
|
||||||
true ->
|
true ->
|
||||||
@ -2810,6 +2865,23 @@ send_out_of_reception_message(StateData, From, To,
|
|||||||
send_out_of_reception_message(StateData, _From, _To, _Packet) ->
|
send_out_of_reception_message(StateData, _From, _To, _Packet) ->
|
||||||
StateData.
|
StateData.
|
||||||
|
|
||||||
|
make_oor_presence(StateData) ->
|
||||||
|
make_oor_presence(StateData, [], []).
|
||||||
|
|
||||||
|
make_oor_presence(StateData, PresenceAttrs, PresenceEls) ->
|
||||||
|
ShowEl =
|
||||||
|
case StateData#state.oor_show of
|
||||||
|
"available" -> [];
|
||||||
|
_ ->
|
||||||
|
[{xmlelement, "show", [],
|
||||||
|
[{xmlcdata, StateData#state.oor_show}]}]
|
||||||
|
end,
|
||||||
|
{xmlelement, "presence", PresenceAttrs,
|
||||||
|
ShowEl ++
|
||||||
|
[{xmlelement, "status", [],
|
||||||
|
[{xmlcdata, StateData#state.oor_status}]}]
|
||||||
|
++ PresenceEls}.
|
||||||
|
|
||||||
utf8_cut(S, Bytes) ->
|
utf8_cut(S, Bytes) ->
|
||||||
utf8_cut(S, [], [], Bytes + 1).
|
utf8_cut(S, [], [], Bytes + 1).
|
||||||
|
|
||||||
@ -2825,6 +2897,47 @@ utf8_cut([C | S], Cur, Prev, Bytes) ->
|
|||||||
utf8_cut(S, [C | Cur], Cur, Bytes - 1)
|
utf8_cut(S, [C | Cur], Cur, Bytes - 1)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-include("mod_roster.hrl").
|
||||||
|
|
||||||
|
get_roster_name(StateData, JID) ->
|
||||||
|
User = StateData#state.user,
|
||||||
|
Server = StateData#state.server,
|
||||||
|
RosterItems = ejabberd_hooks:run_fold(
|
||||||
|
roster_get, Server, [], [{User, Server}]),
|
||||||
|
JUser = JID#jid.luser,
|
||||||
|
JServer = JID#jid.lserver,
|
||||||
|
Item =
|
||||||
|
lists:foldl(
|
||||||
|
fun(_, Res = #roster{}) ->
|
||||||
|
Res;
|
||||||
|
(I, false) ->
|
||||||
|
case I#roster.jid of
|
||||||
|
{JUser, JServer, _} ->
|
||||||
|
I;
|
||||||
|
_ ->
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end, false, RosterItems),
|
||||||
|
case Item of
|
||||||
|
false ->
|
||||||
|
unescape(JID#jid.user);
|
||||||
|
#roster{} ->
|
||||||
|
Item#roster.name
|
||||||
|
end.
|
||||||
|
|
||||||
|
unescape("") -> "";
|
||||||
|
unescape("\\20" ++ S) -> [$\s | unescape(S)];
|
||||||
|
unescape("\\22" ++ S) -> [$" | unescape(S)];
|
||||||
|
unescape("\\26" ++ S) -> [$& | unescape(S)];
|
||||||
|
unescape("\\27" ++ S) -> [$' | unescape(S)];
|
||||||
|
unescape("\\2f" ++ S) -> [$/ | unescape(S)];
|
||||||
|
unescape("\\3a" ++ S) -> [$: | unescape(S)];
|
||||||
|
unescape("\\3c" ++ S) -> [$< | unescape(S)];
|
||||||
|
unescape("\\3e" ++ S) -> [$> | unescape(S)];
|
||||||
|
unescape("\\40" ++ S) -> [$@ | unescape(S)];
|
||||||
|
unescape("\\5c" ++ S) -> [$\\ | unescape(S)];
|
||||||
|
unescape([C | S]) -> [C | unescape(S)].
|
||||||
|
|
||||||
|
|
||||||
cancel_timer(Timer) ->
|
cancel_timer(Timer) ->
|
||||||
erlang:cancel_timer(Timer),
|
erlang:cancel_timer(Timer),
|
||||||
@ -2873,17 +2986,13 @@ enqueue(StateData, From, To, Packet) ->
|
|||||||
StateData#state{pres_queue = NewQueue}
|
StateData#state{pres_queue = NewQueue}
|
||||||
end;
|
end;
|
||||||
true ->
|
true ->
|
||||||
CleanPacket = xml:remove_subtags(
|
CleanPacket = xml:remove_subtags(Packet, "x", {"xmlns", ?NS_P1_PUSHED}),
|
||||||
xml:remove_subtags(Packet, "x", {"xmlns", ?NS_P1_PUSHED}),
|
|
||||||
"x", {"xmlns", ?NS_DELAY91}),
|
|
||||||
Packet2 =
|
Packet2 =
|
||||||
case CleanPacket of
|
case CleanPacket of
|
||||||
{xmlelement, "message" = Name, Attrs, Els} ->
|
{xmlelement, "message", _, _} ->
|
||||||
{xmlelement, Name, Attrs,
|
xml:append_subtags(
|
||||||
Els ++
|
maybe_add_delay(CleanPacket, utc, To, ""),
|
||||||
[jlib:timestamp_to_xml(
|
[{xmlelement, "x", [{"xmlns", ?NS_P1_PUSHED}], []}]);
|
||||||
calendar:now_to_universal_time(now())),
|
|
||||||
{xmlelement, "x", [{"xmlns", ?NS_P1_PUSHED}], []}]};
|
|
||||||
_ ->
|
_ ->
|
||||||
Packet
|
Packet
|
||||||
end,
|
end,
|
||||||
@ -3025,15 +3134,6 @@ rebind(StateData, JID, StreamID) ->
|
|||||||
[StateData#state.socket,
|
[StateData#state.socket,
|
||||||
jlib:jid_to_string(JID)]),
|
jlib:jid_to_string(JID)]),
|
||||||
SID = {now(), self()},
|
SID = {now(), self()},
|
||||||
Conn = get_conn_type(NewStateData),
|
|
||||||
Info = [{ip, StateData#state.ip}, {conn, Conn},
|
|
||||||
{auth_module, NewStateData#state.auth_module}],
|
|
||||||
ejabberd_sm:open_session(
|
|
||||||
SID,
|
|
||||||
NewStateData#state.user,
|
|
||||||
NewStateData#state.server,
|
|
||||||
NewStateData#state.resource,
|
|
||||||
Info),
|
|
||||||
StateData2 =
|
StateData2 =
|
||||||
NewStateData#state{
|
NewStateData#state{
|
||||||
socket = StateData#state.socket,
|
socket = StateData#state.socket,
|
||||||
@ -3044,22 +3144,11 @@ rebind(StateData, JID, StreamID) ->
|
|||||||
keepalive_timer = StateData#state.keepalive_timer,
|
keepalive_timer = StateData#state.keepalive_timer,
|
||||||
ack_timer = undefined
|
ack_timer = undefined
|
||||||
},
|
},
|
||||||
Presence = StateData2#state.pres_last,
|
|
||||||
case Presence of
|
|
||||||
undefined ->
|
|
||||||
ok;
|
|
||||||
_ ->
|
|
||||||
NewPriority = get_priority_from_presence(Presence),
|
|
||||||
update_priority(NewPriority, Presence, StateData2)
|
|
||||||
end,
|
|
||||||
send_element(StateData2,
|
send_element(StateData2,
|
||||||
{xmlelement, "rebind",
|
{xmlelement, "rebind",
|
||||||
[{"xmlns", ?NS_P1_REBIND}],
|
[{"xmlns", ?NS_P1_REBIND}],
|
||||||
[]}),
|
[]}),
|
||||||
StateData3 = change_reception(StateData2, true),
|
maybe_migrate(session_established, StateData2)
|
||||||
StateData4 = start_keepalive_timer(StateData3),
|
|
||||||
fsm_next_state(session_established,
|
|
||||||
StateData4)
|
|
||||||
after 1000 ->
|
after 1000 ->
|
||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
{xmlelement, "failure",
|
{xmlelement, "failure",
|
||||||
@ -3221,6 +3310,33 @@ check_x_attachment1([El | Els]) ->
|
|||||||
check_x_attachment1(Els)
|
check_x_attachment1(Els)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
%% TODO: Delete XEP-0091 stuff once it is Obsolete
|
||||||
|
maybe_add_delay(El, TZ, From, Desc) ->
|
||||||
|
maybe_add_delay(El, TZ, From, Desc, calendar:now_to_universal_time(now())).
|
||||||
|
maybe_add_delay({xmlelement, _, _, Els} = El, TZ, From, Desc, TimeStamp) ->
|
||||||
|
HasOldTS = lists:any(
|
||||||
|
fun({xmlelement, "x", Attrs, _}) ->
|
||||||
|
xml:get_attr_s("xmlns", Attrs) == ?NS_DELAY91;
|
||||||
|
(_) ->
|
||||||
|
false
|
||||||
|
end, Els),
|
||||||
|
HasNewTS = lists:any(
|
||||||
|
fun({xmlelement, "delay", Attrs, _}) ->
|
||||||
|
xml:get_attr_s("xmlns", Attrs) == ?NS_DELAY;
|
||||||
|
(_) ->
|
||||||
|
false
|
||||||
|
end, Els),
|
||||||
|
El1 = if not HasOldTS ->
|
||||||
|
xml:append_subtags(El, [jlib:timestamp_to_xml(TimeStamp)]);
|
||||||
|
true ->
|
||||||
|
El
|
||||||
|
end,
|
||||||
|
if not HasNewTS ->
|
||||||
|
xml:append_subtags(
|
||||||
|
El1, [jlib:timestamp_to_xml(TimeStamp, TZ, From, Desc)]);
|
||||||
|
true ->
|
||||||
|
El1
|
||||||
|
end.
|
||||||
|
|
||||||
send_from(El) ->
|
send_from(El) ->
|
||||||
%% First test previous version attribute:
|
%% First test previous version attribute:
|
||||||
@ -3233,6 +3349,7 @@ send_from(El) ->
|
|||||||
case xml:get_path_s(El, [{elem, "body"}, {attr, "from"}]) of
|
case xml:get_path_s(El, [{elem, "body"}, {attr, "from"}]) of
|
||||||
"jid" -> jid;
|
"jid" -> jid;
|
||||||
"username" -> username;
|
"username" -> username;
|
||||||
|
"name" -> name;
|
||||||
"none" -> none;
|
"none" -> none;
|
||||||
_ -> jid
|
_ -> jid
|
||||||
end
|
end
|
||||||
@ -3260,6 +3377,51 @@ bounce_messages() ->
|
|||||||
ok
|
ok
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
%%% XEP-0191
|
||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
|
route_blocking(What, StateData) ->
|
||||||
|
SubEl =
|
||||||
|
case What of
|
||||||
|
{block, JIDs} ->
|
||||||
|
{xmlelement, "block",
|
||||||
|
[{"xmlns", ?NS_BLOCKING}],
|
||||||
|
lists:map(
|
||||||
|
fun(JID) ->
|
||||||
|
{xmlelement, "item",
|
||||||
|
[{"jid", jlib:jid_to_string(JID)}],
|
||||||
|
[]}
|
||||||
|
end, JIDs)};
|
||||||
|
{unblock, JIDs} ->
|
||||||
|
{xmlelement, "unblock",
|
||||||
|
[{"xmlns", ?NS_BLOCKING}],
|
||||||
|
lists:map(
|
||||||
|
fun(JID) ->
|
||||||
|
{xmlelement, "item",
|
||||||
|
[{"jid", jlib:jid_to_string(JID)}],
|
||||||
|
[]}
|
||||||
|
end, JIDs)};
|
||||||
|
unblock_all ->
|
||||||
|
{xmlelement, "unblock",
|
||||||
|
[{"xmlns", ?NS_BLOCKING}], []}
|
||||||
|
end,
|
||||||
|
PrivPushIQ =
|
||||||
|
#iq{type = set, xmlns = ?NS_BLOCKING,
|
||||||
|
id = "push",
|
||||||
|
sub_el = [SubEl]},
|
||||||
|
PrivPushEl =
|
||||||
|
jlib:replace_from_to(
|
||||||
|
jlib:jid_remove_resource(
|
||||||
|
StateData#state.jid),
|
||||||
|
StateData#state.jid,
|
||||||
|
jlib:iq_to_xml(PrivPushIQ)),
|
||||||
|
send_element(StateData, PrivPushEl),
|
||||||
|
%% No need to replace active privacy list here,
|
||||||
|
%% blocking pushes are always accompanied by
|
||||||
|
%% Privacy List pushes
|
||||||
|
ok.
|
||||||
|
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
%%% JID Set memory footprint reduction code
|
%%% JID Set memory footprint reduction code
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
@ -3333,3 +3495,39 @@ flash_policy_string() ->
|
|||||||
++ ToPortsString ++
|
++ ToPortsString ++
|
||||||
"\"/>\n"
|
"\"/>\n"
|
||||||
"</cross-domain-policy>\n\0".
|
"</cross-domain-policy>\n\0".
|
||||||
|
|
||||||
|
need_redirect(#state{redirect = true, user = User, server = Server}) ->
|
||||||
|
LUser = jlib:nodeprep(User),
|
||||||
|
LServer = jlib:nameprep(Server),
|
||||||
|
case ejabberd_cluster:get_node({LUser, LServer}) of
|
||||||
|
Node when node() == Node ->
|
||||||
|
false;
|
||||||
|
Node ->
|
||||||
|
case rpc:call(Node, ejabberd_config,
|
||||||
|
get_local_option, [hostname], 5000) of
|
||||||
|
Host when is_list(Host) ->
|
||||||
|
{true, Host};
|
||||||
|
_ ->
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
need_redirect(_) ->
|
||||||
|
false.
|
||||||
|
|
||||||
|
get_jid_from_opts(Opts) ->
|
||||||
|
case lists:keysearch(jid, 1, Opts) of
|
||||||
|
{value, {_, JIDValue}} ->
|
||||||
|
JID = case JIDValue of
|
||||||
|
{_U, _S, _R} ->
|
||||||
|
jlib:make_jid(JIDValue);
|
||||||
|
_ when is_binary(JIDValue) ->
|
||||||
|
jlib:string_to_jid(binary_to_list(JIDValue));
|
||||||
|
_ when is_list(JIDValue) ->
|
||||||
|
jlib:string_to_jid(JIDValue);
|
||||||
|
_ ->
|
||||||
|
JIDValue
|
||||||
|
end,
|
||||||
|
{ok, JID};
|
||||||
|
_ ->
|
||||||
|
error
|
||||||
|
end.
|
||||||
|
@ -57,6 +57,7 @@
|
|||||||
conn = unknown,
|
conn = unknown,
|
||||||
auth_module = unknown,
|
auth_module = unknown,
|
||||||
ip,
|
ip,
|
||||||
|
redirect = false,
|
||||||
aux_fields = [],
|
aux_fields = [],
|
||||||
fsm_limit_opts,
|
fsm_limit_opts,
|
||||||
lang,
|
lang,
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
%%% Created : 2 Nov 2007 by Mickael Remond <mremond@process-one.net>
|
%%% Created : 2 Nov 2007 by Mickael Remond <mremond@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% 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>
|
%%% Created : 26 Apr 2008 by Evgeniy Khramtsov <xramtsov@gmail.com>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
@ -35,9 +35,9 @@
|
|||||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||||
terminate/2, code_change/3]).
|
terminate/2, code_change/3]).
|
||||||
|
|
||||||
-export([create_captcha/5, build_captcha_html/2, check_captcha/2,
|
-export([create_captcha/6, build_captcha_html/2, check_captcha/2,
|
||||||
process_reply/1, process/2, is_feature_available/0,
|
process_reply/1, process/2, is_feature_available/0,
|
||||||
create_captcha_x/4, create_captcha_x/5]).
|
create_captcha_x/5, create_captcha_x/6]).
|
||||||
|
|
||||||
-include("jlib.hrl").
|
-include("jlib.hrl").
|
||||||
-include("ejabberd.hrl").
|
-include("ejabberd.hrl").
|
||||||
@ -50,8 +50,9 @@
|
|||||||
-define(CAPTCHA_TEXT(Lang), translate:translate(Lang, "Enter the text you see")).
|
-define(CAPTCHA_TEXT(Lang), translate:translate(Lang, "Enter the text you see")).
|
||||||
-define(CAPTCHA_LIFETIME, 120000). % two minutes
|
-define(CAPTCHA_LIFETIME, 120000). % two minutes
|
||||||
-define(RPC_TIMEOUT, 5000).
|
-define(RPC_TIMEOUT, 5000).
|
||||||
|
-define(LIMIT_PERIOD, 60*1000*1000). % one minute
|
||||||
|
|
||||||
-record(state, {}).
|
-record(state, {limits = treap:empty()}).
|
||||||
-record(captcha, {id, pid, key, tref, args}).
|
-record(captcha, {id, pid, key, tref, args}).
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
@ -64,10 +65,10 @@
|
|||||||
start_link() ->
|
start_link() ->
|
||||||
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
|
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
|
||||||
|
|
||||||
create_captcha(SID, From, To, Lang, Args)
|
create_captcha(SID, From, To, Lang, Limiter, Args)
|
||||||
when is_list(Lang), is_list(SID),
|
when is_list(Lang), is_list(SID),
|
||||||
is_record(From, jid), is_record(To, jid) ->
|
is_record(From, jid), is_record(To, jid) ->
|
||||||
case create_image() of
|
case create_image(Limiter) of
|
||||||
{ok, Type, Key, Image} ->
|
{ok, Type, Key, Image} ->
|
||||||
Id = randoms:get_string() ++ "-" ++ ejabberd_cluster:node_id(),
|
Id = randoms:get_string() ++ "-" ++ ejabberd_cluster:node_id(),
|
||||||
B64Image = jlib:encode_base64(binary_to_list(Image)),
|
B64Image = jlib:encode_base64(binary_to_list(Image)),
|
||||||
@ -99,15 +100,15 @@ create_captcha(SID, From, To, Lang, Args)
|
|||||||
ets:insert(captcha, #captcha{id=Id, pid=self(), key=Key,
|
ets:insert(captcha, #captcha{id=Id, pid=self(), key=Key,
|
||||||
tref=Tref, args=Args}),
|
tref=Tref, args=Args}),
|
||||||
{ok, Id, [Body, OOB, Captcha, Data]};
|
{ok, Id, [Body, OOB, Captcha, Data]};
|
||||||
_Err ->
|
Err ->
|
||||||
error
|
Err
|
||||||
end.
|
end.
|
||||||
|
|
||||||
create_captcha_x(SID, To, Lang, HeadEls) ->
|
create_captcha_x(SID, To, Lang, Limiter, HeadEls) ->
|
||||||
create_captcha_x(SID, To, Lang, HeadEls, []).
|
create_captcha_x(SID, To, Lang, Limiter, HeadEls, []).
|
||||||
|
|
||||||
create_captcha_x(SID, To, Lang, HeadEls, TailEls) ->
|
create_captcha_x(SID, To, Lang, Limiter, HeadEls, TailEls) ->
|
||||||
case create_image() of
|
case create_image(Limiter) of
|
||||||
{ok, Type, Key, Image} ->
|
{ok, Type, Key, Image} ->
|
||||||
Id = randoms:get_string() ++ "-" ++ ejabberd_cluster:node_id(),
|
Id = randoms:get_string() ++ "-" ++ ejabberd_cluster:node_id(),
|
||||||
B64Image = jlib:encode_base64(binary_to_list(Image)),
|
B64Image = jlib:encode_base64(binary_to_list(Image)),
|
||||||
@ -144,8 +145,8 @@ create_captcha_x(SID, To, Lang, HeadEls, TailEls) ->
|
|||||||
Tref = erlang:send_after(?CAPTCHA_LIFETIME, ?MODULE, {remove_id, Id}),
|
Tref = erlang:send_after(?CAPTCHA_LIFETIME, ?MODULE, {remove_id, Id}),
|
||||||
ets:insert(captcha, #captcha{id=Id, key=Key, tref=Tref}),
|
ets:insert(captcha, #captcha{id=Id, key=Key, tref=Tref}),
|
||||||
{ok, [Captcha, Data]};
|
{ok, [Captcha, Data]};
|
||||||
_ ->
|
Err ->
|
||||||
error
|
Err
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% @spec (Id::string(), Lang::string()) -> {FormEl, {ImgEl, TextEl, IdEl, KeyEl}} | captcha_not_found
|
%% @spec (Id::string(), Lang::string()) -> {FormEl, {ImgEl, TextEl, IdEl, KeyEl}} | captcha_not_found
|
||||||
@ -242,16 +243,19 @@ process(_Handlers, #request{method='GET', lang=Lang, path=[_, Id]}) ->
|
|||||||
ejabberd_web:error(not_found)
|
ejabberd_web:error(not_found)
|
||||||
end;
|
end;
|
||||||
|
|
||||||
process(_Handlers, #request{method='GET', path=[_, Id, "image"]}) ->
|
process(_Handlers, #request{method='GET', path=[_, Id, "image"], ip = IP}) ->
|
||||||
|
{Addr, _Port} = IP,
|
||||||
case lookup_captcha(Id) of
|
case lookup_captcha(Id) of
|
||||||
{ok, #captcha{key=Key}} ->
|
{ok, #captcha{key=Key}} ->
|
||||||
case create_image(Key) of
|
case create_image(Addr, Key) of
|
||||||
{ok, Type, _, Img} ->
|
{ok, Type, _, Img} ->
|
||||||
{200,
|
{200,
|
||||||
[{"Content-Type", Type},
|
[{"Content-Type", Type},
|
||||||
{"Cache-Control", "no-cache"},
|
{"Cache-Control", "no-cache"},
|
||||||
{"Last-Modified", httpd_util:rfc1123_date()}],
|
{"Last-Modified", httpd_util:rfc1123_date()}],
|
||||||
Img};
|
Img};
|
||||||
|
{error, limit} ->
|
||||||
|
ejabberd_web:error(not_allowed);
|
||||||
_ ->
|
_ ->
|
||||||
ejabberd_web:error(not_found)
|
ejabberd_web:error(not_found)
|
||||||
end;
|
end;
|
||||||
@ -288,6 +292,20 @@ init([]) ->
|
|||||||
check_captcha_setup(),
|
check_captcha_setup(),
|
||||||
{ok, #state{}}.
|
{ok, #state{}}.
|
||||||
|
|
||||||
|
handle_call({is_limited, Limiter, RateLimit}, _From, State) ->
|
||||||
|
NowPriority = now_priority(),
|
||||||
|
CleanPriority = NowPriority + ?LIMIT_PERIOD,
|
||||||
|
Limits = clean_treap(State#state.limits, CleanPriority),
|
||||||
|
case treap:lookup(Limiter, Limits) of
|
||||||
|
{ok, _, Rate} when Rate >= RateLimit ->
|
||||||
|
{reply, true, State#state{limits = Limits}};
|
||||||
|
{ok, Priority, Rate} ->
|
||||||
|
NewLimits = treap:insert(Limiter, Priority, Rate+1, Limits),
|
||||||
|
{reply, false, State#state{limits = NewLimits}};
|
||||||
|
_ ->
|
||||||
|
NewLimits = treap:insert(Limiter, NowPriority, 1, Limits),
|
||||||
|
{reply, false, State#state{limits = NewLimits}}
|
||||||
|
end;
|
||||||
handle_call(_Request, _From, State) ->
|
handle_call(_Request, _From, State) ->
|
||||||
{reply, bad_request, State}.
|
{reply, bad_request, State}.
|
||||||
|
|
||||||
@ -329,11 +347,22 @@ code_change(_OldVsn, State, _Extra) ->
|
|||||||
%% Reason = atom()
|
%% Reason = atom()
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
create_image() ->
|
create_image() ->
|
||||||
|
create_image(undefined).
|
||||||
|
|
||||||
|
create_image(Limiter) ->
|
||||||
%% Six numbers from 1 to 9.
|
%% Six numbers from 1 to 9.
|
||||||
Key = string:substr(randoms:get_string(), 1, 6),
|
Key = string:substr(randoms:get_string(), 1, 6),
|
||||||
create_image(Key).
|
create_image(Limiter, Key).
|
||||||
|
|
||||||
create_image(Key) ->
|
create_image(Limiter, Key) ->
|
||||||
|
case is_limited(Limiter) of
|
||||||
|
true ->
|
||||||
|
{error, limit};
|
||||||
|
false ->
|
||||||
|
do_create_image(Key)
|
||||||
|
end.
|
||||||
|
|
||||||
|
do_create_image(Key) ->
|
||||||
FileName = get_prog_name(),
|
FileName = get_prog_name(),
|
||||||
Cmd = lists:flatten(io_lib:format("~s ~s", [FileName, Key])),
|
Cmd = lists:flatten(io_lib:format("~s ~s", [FileName, Key])),
|
||||||
case cmd(Cmd) of
|
case cmd(Cmd) of
|
||||||
@ -363,20 +392,82 @@ get_prog_name() ->
|
|||||||
case ejabberd_config:get_local_option(captcha_cmd) of
|
case ejabberd_config:get_local_option(captcha_cmd) of
|
||||||
FileName when is_list(FileName) ->
|
FileName when is_list(FileName) ->
|
||||||
FileName;
|
FileName;
|
||||||
_ ->
|
Value when (Value == undefined) or (Value == "") ->
|
||||||
?DEBUG("The option captcha_cmd is not configured, but some "
|
?DEBUG("The option captcha_cmd is not configured, but some "
|
||||||
"module wants to use the CAPTCHA feature.", []),
|
"module wants to use the CAPTCHA feature.", []),
|
||||||
throw({error, option_not_configured_captcha_cmd})
|
false
|
||||||
end.
|
end.
|
||||||
|
|
||||||
get_url(Str) ->
|
get_url(Str) ->
|
||||||
case ejabberd_config:get_local_option(captcha_host) of
|
CaptchaHost = ejabberd_config:get_local_option(captcha_host),
|
||||||
Host when is_list(Host) ->
|
case string:tokens(CaptchaHost, ":") of
|
||||||
|
[Host] ->
|
||||||
"http://" ++ Host ++ "/captcha/" ++ Str;
|
"http://" ++ Host ++ "/captcha/" ++ Str;
|
||||||
|
["http"++_ = TransferProt, Host] ->
|
||||||
|
TransferProt ++ ":" ++ Host ++ "/captcha/" ++ Str;
|
||||||
|
[Host, PortString] ->
|
||||||
|
TransferProt = atom_to_list(get_transfer_protocol(PortString)),
|
||||||
|
TransferProt ++ "://" ++ Host ++ ":" ++ PortString ++ "/captcha/" ++ Str;
|
||||||
|
[TransferProt, Host, PortString] ->
|
||||||
|
TransferProt ++ ":" ++ Host ++ ":" ++ PortString ++ "/captcha/" ++ Str;
|
||||||
_ ->
|
_ ->
|
||||||
"http://" ++ ?MYNAME ++ "/captcha/" ++ Str
|
"http://" ++ ?MYNAME ++ "/captcha/" ++ Str
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
get_transfer_protocol(PortString) ->
|
||||||
|
PortNumber = list_to_integer(PortString),
|
||||||
|
PortListeners = get_port_listeners(PortNumber),
|
||||||
|
get_captcha_transfer_protocol(PortListeners).
|
||||||
|
|
||||||
|
get_port_listeners(PortNumber) ->
|
||||||
|
AllListeners = ejabberd_config:get_local_option(listen),
|
||||||
|
lists:filter(
|
||||||
|
fun({{Port, _Ip, _Netp}, _Module1, _Opts1}) when Port == PortNumber ->
|
||||||
|
true;
|
||||||
|
(_) ->
|
||||||
|
false
|
||||||
|
end,
|
||||||
|
AllListeners).
|
||||||
|
|
||||||
|
get_captcha_transfer_protocol([]) ->
|
||||||
|
throw("The port number mentioned in captcha_host is not "
|
||||||
|
"a ejabberd_http listener with 'captcha' option. "
|
||||||
|
"Change the port number or specify http:// in that option.");
|
||||||
|
get_captcha_transfer_protocol([{{_Port, _Ip, tcp}, ejabberd_http, Opts}
|
||||||
|
| Listeners]) ->
|
||||||
|
case lists:member(captcha, Opts) of
|
||||||
|
true ->
|
||||||
|
case lists:member(tls, Opts) of
|
||||||
|
true ->
|
||||||
|
https;
|
||||||
|
false ->
|
||||||
|
http
|
||||||
|
end;
|
||||||
|
false ->
|
||||||
|
get_captcha_transfer_protocol(Listeners)
|
||||||
|
end;
|
||||||
|
get_captcha_transfer_protocol([_ | Listeners]) ->
|
||||||
|
get_captcha_transfer_protocol(Listeners).
|
||||||
|
|
||||||
|
is_limited(undefined) ->
|
||||||
|
false;
|
||||||
|
is_limited(Limiter) ->
|
||||||
|
case ejabberd_config:get_local_option(captcha_limit) of
|
||||||
|
Int when is_integer(Int), Int > 0 ->
|
||||||
|
case catch gen_server:call(?MODULE, {is_limited, Limiter, Int},
|
||||||
|
5000) of
|
||||||
|
true ->
|
||||||
|
true;
|
||||||
|
false ->
|
||||||
|
false;
|
||||||
|
Err ->
|
||||||
|
?ERROR_MSG("Call failed: ~p", [Err]),
|
||||||
|
false
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
false
|
||||||
|
end.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Function: cmd(Cmd) -> Data | {error, Reason}
|
%% Function: cmd(Cmd) -> Data | {error, Reason}
|
||||||
%% Cmd = string()
|
%% Cmd = string()
|
||||||
@ -425,28 +516,23 @@ return(Port, TRef, Result) ->
|
|||||||
catch port_close(Port),
|
catch port_close(Port),
|
||||||
Result.
|
Result.
|
||||||
|
|
||||||
is_feature_enabled() ->
|
|
||||||
try get_prog_name() of
|
|
||||||
Prog when is_list(Prog) -> true
|
|
||||||
catch
|
|
||||||
_:_ -> false
|
|
||||||
end.
|
|
||||||
|
|
||||||
is_feature_available() ->
|
is_feature_available() ->
|
||||||
case is_feature_enabled() of
|
case get_prog_name() of
|
||||||
false -> false;
|
Prog when is_list(Prog) -> true;
|
||||||
true ->
|
false -> false
|
||||||
case create_image() of
|
|
||||||
{ok, _, _, _} -> true;
|
|
||||||
_Error -> false
|
|
||||||
end
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
check_captcha_setup() ->
|
check_captcha_setup() ->
|
||||||
case is_feature_enabled() andalso not is_feature_available() of
|
case is_feature_available() of
|
||||||
true ->
|
true ->
|
||||||
|
case create_image() of
|
||||||
|
{ok, _, _, _} ->
|
||||||
|
ok;
|
||||||
|
_Err ->
|
||||||
?CRITICAL_MSG("Captcha is enabled in the option captcha_cmd, "
|
?CRITICAL_MSG("Captcha is enabled in the option captcha_cmd, "
|
||||||
"but it can't generate images.", []);
|
"but it can't generate images.", []),
|
||||||
|
throw({error, captcha_cmd_enabled_but_fails})
|
||||||
|
end;
|
||||||
false ->
|
false ->
|
||||||
ok
|
ok
|
||||||
end.
|
end.
|
||||||
@ -498,3 +584,21 @@ do_check_captcha(Id, ProvidedKey) ->
|
|||||||
_ ->
|
_ ->
|
||||||
captcha_not_found
|
captcha_not_found
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
clean_treap(Treap, CleanPriority) ->
|
||||||
|
case treap:is_empty(Treap) of
|
||||||
|
true ->
|
||||||
|
Treap;
|
||||||
|
false ->
|
||||||
|
{_Key, Priority, _Value} = treap:get_root(Treap),
|
||||||
|
if
|
||||||
|
Priority > CleanPriority ->
|
||||||
|
clean_treap(treap:delete_root(Treap), CleanPriority);
|
||||||
|
true ->
|
||||||
|
Treap
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
|
now_priority() ->
|
||||||
|
{MSec, Sec, USec} = now(),
|
||||||
|
-((MSec*1000000 + Sec)*1000000 + USec).
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 27 Feb 2008 by Mickael Remond <mremond@process-one.net>
|
%%% Created : 27 Feb 2008 by Mickael Remond <mremond@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -10,8 +10,8 @@
|
|||||||
-behaviour(gen_server).
|
-behaviour(gen_server).
|
||||||
|
|
||||||
%% API
|
%% API
|
||||||
-export([start_link/0, get_node/1, get_node_new/1, announce/0, shutdown/0,
|
-export([start_link/0, get_node/1, get_node_new/1, announce/1, shutdown/0,
|
||||||
node_id/0, get_node_by_id/1, get_nodes/0, rehash_timeout/0]).
|
node_id/0, get_node_by_id/1, get_nodes/0, rehash_timeout/0, start/0]).
|
||||||
|
|
||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||||
@ -22,15 +22,28 @@
|
|||||||
-define(HASHTBL, nodes_hash).
|
-define(HASHTBL, nodes_hash).
|
||||||
-define(HASHTBL_NEW, nodes_hash_new).
|
-define(HASHTBL_NEW, nodes_hash_new).
|
||||||
-define(POINTS, 64).
|
-define(POINTS, 64).
|
||||||
-define(REHASH_TIMEOUT, 30000).
|
-define(REHASH_TIMEOUT, timer:seconds(30)).
|
||||||
|
-define(MIGRATE_TIMEOUT, timer:minutes(2)).
|
||||||
|
%%-define(REHASH_TIMEOUT, timer:seconds(10)).
|
||||||
|
%%-define(MIGRATE_TIMEOUT, timer:seconds(5)).
|
||||||
|
-define(LOCK, {migrate, node()}).
|
||||||
|
|
||||||
-record(state, {}).
|
-record(state, {}).
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% API
|
%% API
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
|
start() ->
|
||||||
|
ChildSpec = {?MODULE,
|
||||||
|
{?MODULE, start_link, []},
|
||||||
|
permanent,
|
||||||
|
brutal_kill,
|
||||||
|
worker,
|
||||||
|
[?MODULE]},
|
||||||
|
supervisor:start_child(ejabberd_sup, ChildSpec).
|
||||||
|
|
||||||
start_link() ->
|
start_link() ->
|
||||||
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
|
gen_server:start_link(?MODULE, [], []).
|
||||||
|
|
||||||
get_node(Key) ->
|
get_node(Key) ->
|
||||||
Hash = erlang:phash2(Key),
|
Hash = erlang:phash2(Key),
|
||||||
@ -44,8 +57,8 @@ get_nodes() ->
|
|||||||
%% TODO
|
%% TODO
|
||||||
mnesia:system_info(running_db_nodes).
|
mnesia:system_info(running_db_nodes).
|
||||||
|
|
||||||
announce() ->
|
announce(Pid) ->
|
||||||
gen_server:call(?MODULE, announce, infinity).
|
gen_server:call(Pid, announce, infinity).
|
||||||
|
|
||||||
node_id() ->
|
node_id() ->
|
||||||
integer_to_list(erlang:phash2(node())).
|
integer_to_list(erlang:phash2(node())).
|
||||||
@ -80,13 +93,15 @@ shutdown() ->
|
|||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
init([]) ->
|
init([]) ->
|
||||||
|
{A, B, C} = now(),
|
||||||
|
random:seed(A, B, C),
|
||||||
net_kernel:monitor_nodes(true, [{node_type, visible}]),
|
net_kernel:monitor_nodes(true, [{node_type, visible}]),
|
||||||
ets:new(?HASHTBL, [named_table, public, ordered_set]),
|
ets:new(?HASHTBL, [named_table, public, ordered_set]),
|
||||||
ets:new(?HASHTBL_NEW, [named_table, public, ordered_set]),
|
ets:new(?HASHTBL_NEW, [named_table, public, ordered_set]),
|
||||||
register_node(),
|
register_node(),
|
||||||
AllNodes = mnesia:system_info(running_db_nodes),
|
AllNodes = get_nodes(),
|
||||||
OtherNodes = case AllNodes of
|
OtherNodes = case AllNodes of
|
||||||
[_] ->
|
[_MyNode] ->
|
||||||
AllNodes;
|
AllNodes;
|
||||||
_ ->
|
_ ->
|
||||||
AllNodes -- [node()]
|
AllNodes -- [node()]
|
||||||
@ -96,35 +111,59 @@ init([]) ->
|
|||||||
{ok, #state{}}.
|
{ok, #state{}}.
|
||||||
|
|
||||||
handle_call(announce, _From, State) ->
|
handle_call(announce, _From, State) ->
|
||||||
case mnesia:system_info(running_db_nodes) of
|
case global:set_lock(?LOCK, get_nodes(), 0) of
|
||||||
|
false ->
|
||||||
|
?INFO_MSG("Another node is recently attached to "
|
||||||
|
"the cluster and is being rebalanced. "
|
||||||
|
"Waiting for the rebalancing to be completed "
|
||||||
|
"before starting this node. "
|
||||||
|
"This may take serveral minutes. "
|
||||||
|
"Please, be patient.", []),
|
||||||
|
global:set_lock(?LOCK, get_nodes(), infinity);
|
||||||
|
true ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
|
case get_nodes() of
|
||||||
[_MyNode] ->
|
[_MyNode] ->
|
||||||
ok;
|
register(?MODULE, self()),
|
||||||
|
global:del_lock(?LOCK);
|
||||||
Nodes ->
|
Nodes ->
|
||||||
OtherNodes = Nodes -- [node()],
|
OtherNodes = Nodes -- [node()],
|
||||||
lists:foreach(
|
|
||||||
fun(Node) ->
|
|
||||||
{?MODULE, Node} ! {node_ready, node()}
|
|
||||||
end, OtherNodes),
|
|
||||||
?INFO_MSG("waiting for migration from nodes: ~w",
|
?INFO_MSG("waiting for migration from nodes: ~w",
|
||||||
[OtherNodes]),
|
[OtherNodes]),
|
||||||
timer:sleep(?REHASH_TIMEOUT),
|
{_Res, BadNodes} = gen_server:multi_call(
|
||||||
append_node(?HASHTBL, node())
|
OtherNodes, ?MODULE,
|
||||||
|
{node_ready, node()}, ?REHASH_TIMEOUT),
|
||||||
|
append_node(?HASHTBL, node()),
|
||||||
|
register(?MODULE, self()),
|
||||||
|
case OtherNodes -- BadNodes of
|
||||||
|
[] ->
|
||||||
|
global:del_lock(?LOCK);
|
||||||
|
WorkingNodes ->
|
||||||
|
gen_server:abcast(WorkingNodes, ?MODULE, {node_ready, node()}),
|
||||||
|
erlang:send_after(?MIGRATE_TIMEOUT, self(), del_lock)
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
{reply, ok, State};
|
{reply, ok, State};
|
||||||
|
handle_call({node_ready, Node}, _From, State) ->
|
||||||
|
?INFO_MSG("node ~p is ready, preparing migration", [Node]),
|
||||||
|
append_node(?HASHTBL_NEW, Node),
|
||||||
|
ejabberd_hooks:run(node_up, [Node]),
|
||||||
|
{reply, ok, State};
|
||||||
handle_call(_Request, _From, State) ->
|
handle_call(_Request, _From, State) ->
|
||||||
Reply = ok,
|
Reply = ok,
|
||||||
{reply, Reply, State}.
|
{reply, Reply, State}.
|
||||||
|
|
||||||
|
handle_cast({node_ready, Node}, State) ->
|
||||||
|
?INFO_MSG("adding node ~p to hash and starting migration", [Node]),
|
||||||
|
append_node(?HASHTBL, Node),
|
||||||
|
ejabberd_hooks:run(node_hash_update, [?MIGRATE_TIMEOUT]),
|
||||||
|
{noreply, State};
|
||||||
handle_cast(_Msg, State) ->
|
handle_cast(_Msg, State) ->
|
||||||
{noreply, State}.
|
{noreply, State}.
|
||||||
|
|
||||||
handle_info({node_ready, Node}, State) ->
|
handle_info(del_lock, State) ->
|
||||||
?INFO_MSG("node ~p is ready, starting migration", [Node]),
|
global:del_lock(?LOCK),
|
||||||
append_node(?HASHTBL_NEW, Node),
|
|
||||||
ejabberd_hooks:run(node_hash_update, [?REHASH_TIMEOUT]),
|
|
||||||
timer:sleep(?REHASH_TIMEOUT),
|
|
||||||
?INFO_MSG("adding node ~p to hash", [Node]),
|
|
||||||
append_node(?HASHTBL, Node),
|
|
||||||
{noreply, State};
|
{noreply, State};
|
||||||
handle_info({node_down, Node}, State) ->
|
handle_info({node_down, Node}, State) ->
|
||||||
delete_node(?HASHTBL, Node),
|
delete_node(?HASHTBL, Node),
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 20 May 2008 by Badlop <badlop@process-one.net>
|
%%% Created : 20 May 2008 by Badlop <badlop@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 14 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 14 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
@ -431,6 +431,8 @@ process_term(Term, State) ->
|
|||||||
add_option(captcha_cmd, Cmd, State);
|
add_option(captcha_cmd, Cmd, State);
|
||||||
{captcha_host, Host} ->
|
{captcha_host, Host} ->
|
||||||
add_option(captcha_host, Host, State);
|
add_option(captcha_host, Host, State);
|
||||||
|
{captcha_limit, Limit} ->
|
||||||
|
add_option(captcha_limit, Limit, State);
|
||||||
{ejabberdctl_access_commands, ACs} ->
|
{ejabberdctl_access_commands, ACs} ->
|
||||||
add_option(ejabberdctl_access_commands, ACs, State);
|
add_option(ejabberdctl_access_commands, ACs, State);
|
||||||
{loglevel, Loglevel} ->
|
{loglevel, Loglevel} ->
|
||||||
@ -438,6 +440,8 @@ process_term(Term, State) ->
|
|||||||
State;
|
State;
|
||||||
{max_fsm_queue, N} ->
|
{max_fsm_queue, N} ->
|
||||||
add_option(max_fsm_queue, N, State);
|
add_option(max_fsm_queue, N, State);
|
||||||
|
{hostname, Host} ->
|
||||||
|
add_option(hostname, Host, State);
|
||||||
{_Opt, _Val} ->
|
{_Opt, _Val} ->
|
||||||
lists:foldl(fun(Host, S) -> process_host_term(Term, Host, S) end,
|
lists:foldl(fun(Host, S) -> process_host_term(Term, Host, S) end,
|
||||||
State, State#state.hosts)
|
State, State#state.hosts)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 11 Jan 2004 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 11 Jan 2004 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% 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>
|
%%% Created : 23 Aug 2006 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% 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>
|
%%% Created : 8 Aug 2004 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% 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>
|
%%% Created : 16 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 30 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 30 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
@ -34,10 +34,12 @@
|
|||||||
|
|
||||||
-export([route/3,
|
-export([route/3,
|
||||||
route_iq/4,
|
route_iq/4,
|
||||||
|
route_iq/5,
|
||||||
process_iq_reply/3,
|
process_iq_reply/3,
|
||||||
register_iq_handler/4,
|
register_iq_handler/4,
|
||||||
register_iq_handler/5,
|
register_iq_handler/5,
|
||||||
register_iq_response_handler/4,
|
register_iq_response_handler/4,
|
||||||
|
register_iq_response_handler/5,
|
||||||
unregister_iq_handler/2,
|
unregister_iq_handler/2,
|
||||||
unregister_iq_response_handler/2,
|
unregister_iq_response_handler/2,
|
||||||
refresh_iq_handlers/0,
|
refresh_iq_handlers/0,
|
||||||
@ -123,19 +125,31 @@ route(From, To, Packet) ->
|
|||||||
ok
|
ok
|
||||||
end.
|
end.
|
||||||
|
|
||||||
route_iq(From, To, #iq{type = Type} = IQ, F) when is_function(F) ->
|
route_iq(From, To, IQ, F) ->
|
||||||
|
route_iq(From, To, IQ, F, undefined).
|
||||||
|
|
||||||
|
route_iq(From, To, #iq{type = Type} = IQ, F, Timeout) when is_function(F) ->
|
||||||
Packet = if Type == set; Type == get ->
|
Packet = if Type == set; Type == get ->
|
||||||
ID = ejabberd_router:make_id(),
|
ID = ejabberd_router:make_id(),
|
||||||
Host = From#jid.lserver,
|
Host = From#jid.lserver,
|
||||||
register_iq_response_handler(Host, ID, undefined, F),
|
register_iq_response_handler(Host, ID, undefined, F, Timeout),
|
||||||
jlib:iq_to_xml(IQ#iq{id = ID});
|
jlib:iq_to_xml(IQ#iq{id = ID});
|
||||||
true ->
|
true ->
|
||||||
jlib:iq_to_xml(IQ)
|
jlib:iq_to_xml(IQ)
|
||||||
end,
|
end,
|
||||||
ejabberd_router:route(From, To, Packet).
|
ejabberd_router:route(From, To, Packet).
|
||||||
|
|
||||||
register_iq_response_handler(_Host, ID, Module, Function) ->
|
register_iq_response_handler(Host, ID, Module, Function) ->
|
||||||
TRef = erlang:start_timer(?IQ_TIMEOUT, ejabberd_local, ID),
|
register_iq_response_handler(Host, ID, Module, Function, undefined).
|
||||||
|
|
||||||
|
register_iq_response_handler(_Host, ID, Module, Function, Timeout0) ->
|
||||||
|
Timeout = case Timeout0 of
|
||||||
|
undefined ->
|
||||||
|
?IQ_TIMEOUT;
|
||||||
|
N when is_integer(N), N > 0 ->
|
||||||
|
N
|
||||||
|
end,
|
||||||
|
TRef = erlang:start_timer(Timeout, ejabberd_local, ID),
|
||||||
ets:insert(iq_response, #iq_response{id = ID,
|
ets:insert(iq_response, #iq_response{id = ID,
|
||||||
module = Module,
|
module = Module,
|
||||||
function = Function,
|
function = Function,
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 23 Oct 2003 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 23 Oct 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% 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>
|
%%% Created : 29 Nov 2006 by Mickael Remond <mremond@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% 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>
|
%%% Created : 1 Nov 2006 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 17 Jul 2008 by Pablo Polvorin <pablo.polvorin@process-one.net>
|
%%% Created : 17 Jul 2008 by Pablo Polvorin <pablo.polvorin@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% 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>
|
%%% Created : 31 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% 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>
|
%%% Created : 10 Nov 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 27 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 27 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 7 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 7 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
@ -203,9 +203,9 @@ migrate(After) ->
|
|||||||
['$$']}]),
|
['$$']}]),
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun([FromTo, Pid]) ->
|
fun([FromTo, Pid]) ->
|
||||||
case ejabberd_cluster:get_node_new(FromTo) of
|
case ejabberd_cluster:get_node(FromTo) of
|
||||||
Node when Node /= node() ->
|
Node when Node /= node() ->
|
||||||
ejabberd_s2s_out:stop_connection(Pid, After * 2);
|
ejabberd_s2s_out:stop_connection(Pid, After);
|
||||||
_ ->
|
_ ->
|
||||||
ok
|
ok
|
||||||
end
|
end
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 6 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 6 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 6 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 6 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
@ -322,6 +322,10 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
|||||||
{"jabber:server", "jabber:server:dialback", true} when
|
{"jabber:server", "jabber:server:dialback", true} when
|
||||||
StateData#state.use_v10 ->
|
StateData#state.use_v10 ->
|
||||||
{next_state, wait_for_features, StateData, ?FSMTIMEOUT};
|
{next_state, wait_for_features, StateData, ?FSMTIMEOUT};
|
||||||
|
%% Clause added to handle Tigase's workaround for an old ejabberd bug:
|
||||||
|
{"jabber:server", "jabber:server:dialback", true} when
|
||||||
|
not StateData#state.use_v10 ->
|
||||||
|
send_db_request(StateData);
|
||||||
{"jabber:server", "", true} when StateData#state.use_v10 ->
|
{"jabber:server", "", true} when StateData#state.use_v10 ->
|
||||||
{next_state, wait_for_features, StateData#state{db_enabled = false}, ?FSMTIMEOUT};
|
{next_state, wait_for_features, StateData#state{db_enabled = false}, ?FSMTIMEOUT};
|
||||||
{NSProvided, DB, _} ->
|
{NSProvided, DB, _} ->
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 6 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 6 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 24 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 24 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
@ -37,9 +37,11 @@
|
|||||||
open_session/6,
|
open_session/6,
|
||||||
close_session/4,
|
close_session/4,
|
||||||
close_migrated_session/4,
|
close_migrated_session/4,
|
||||||
|
drop_session/1,
|
||||||
check_in_subscription/6,
|
check_in_subscription/6,
|
||||||
bounce_offline_message/3,
|
bounce_offline_message/3,
|
||||||
disconnect_removed_user/2,
|
disconnect_removed_user/2,
|
||||||
|
get_user_sessions/2,
|
||||||
get_user_resources/2,
|
get_user_resources/2,
|
||||||
set_presence/7,
|
set_presence/7,
|
||||||
unset_presence/6,
|
unset_presence/6,
|
||||||
@ -59,6 +61,7 @@
|
|||||||
get_session_pid/3,
|
get_session_pid/3,
|
||||||
get_user_info/3,
|
get_user_info/3,
|
||||||
get_user_ip/3,
|
get_user_ip/3,
|
||||||
|
node_up/1,
|
||||||
migrate/1
|
migrate/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
@ -107,27 +110,37 @@ open_session(SID, User, Server, Resource, Priority, Info) ->
|
|||||||
[SID, JID, Info]).
|
[SID, JID, Info]).
|
||||||
|
|
||||||
close_session(SID, User, Server, Resource) ->
|
close_session(SID, User, Server, Resource) ->
|
||||||
Info = do_close_session(SID, User, Server, Resource),
|
Info = do_close_session(SID),
|
||||||
|
US = {jlib:nodeprep(User), jlib:nameprep(Server)},
|
||||||
|
case ejabberd_cluster:get_node_new(US) of
|
||||||
|
Node when Node /= node() ->
|
||||||
|
rpc:cast(Node, ?MODULE, drop_session, [SID]);
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
JID = jlib:make_jid(User, Server, Resource),
|
JID = jlib:make_jid(User, Server, Resource),
|
||||||
ejabberd_hooks:run(sm_remove_connection_hook, JID#jid.lserver,
|
ejabberd_hooks:run(sm_remove_connection_hook, JID#jid.lserver,
|
||||||
[SID, JID, Info]).
|
[SID, JID, Info]).
|
||||||
|
|
||||||
close_migrated_session(SID, User, Server, Resource) ->
|
close_migrated_session(SID, User, Server, Resource) ->
|
||||||
Info = do_close_session(SID, User, Server, Resource),
|
Info = do_close_session(SID),
|
||||||
JID = jlib:make_jid(User, Server, Resource),
|
JID = jlib:make_jid(User, Server, Resource),
|
||||||
ejabberd_hooks:run(sm_remove_migrated_connection_hook, JID#jid.lserver,
|
ejabberd_hooks:run(sm_remove_migrated_connection_hook, JID#jid.lserver,
|
||||||
[SID, JID, Info]).
|
[SID, JID, Info]).
|
||||||
|
|
||||||
do_close_session(SID, User, Server, Resource) ->
|
do_close_session(SID) ->
|
||||||
Info = case mnesia:dirty_read({session, SID}) of
|
Info = case mnesia:dirty_read({session, SID}) of
|
||||||
[] -> [];
|
[] -> [];
|
||||||
[#session{info=I}] -> I
|
[#session{info=I}] -> I
|
||||||
end,
|
end,
|
||||||
|
drop_session(SID),
|
||||||
|
Info.
|
||||||
|
|
||||||
|
drop_session(SID) ->
|
||||||
F = fun() ->
|
F = fun() ->
|
||||||
mnesia:delete({session, SID})
|
mnesia:delete({session, SID})
|
||||||
end,
|
end,
|
||||||
mnesia:sync_dirty(F),
|
mnesia:sync_dirty(F).
|
||||||
Info.
|
|
||||||
|
|
||||||
check_in_subscription(Acc, User, Server, _JID, _Type, _Reason) ->
|
check_in_subscription(Acc, User, Server, _JID, _Type, _Reason) ->
|
||||||
case ejabberd_auth:is_user_exists(User, Server) of
|
case ejabberd_auth:is_user_exists(User, Server) of
|
||||||
@ -148,6 +161,18 @@ disconnect_removed_user(User, Server) ->
|
|||||||
{xmlelement, "broadcast", [],
|
{xmlelement, "broadcast", [],
|
||||||
[{exit, "User removed"}]}).
|
[{exit, "User removed"}]}).
|
||||||
|
|
||||||
|
get_user_sessions(User, Server) ->
|
||||||
|
LUser = jlib:nodeprep(User),
|
||||||
|
LServer = jlib:nameprep(Server),
|
||||||
|
US = {LUser, LServer},
|
||||||
|
case ejabberd_cluster:get_node({LUser, LServer}) of
|
||||||
|
Node when Node == node() ->
|
||||||
|
catch mnesia:dirty_index_read(session, US, #session.us);
|
||||||
|
Node ->
|
||||||
|
catch rpc:call(Node, mnesia, dirty_index_read,
|
||||||
|
[session, US, #session.us], 5000)
|
||||||
|
end.
|
||||||
|
|
||||||
get_user_resources(User, Server) ->
|
get_user_resources(User, Server) ->
|
||||||
LUser = jlib:nodeprep(User),
|
LUser = jlib:nodeprep(User),
|
||||||
LServer = jlib:nameprep(Server),
|
LServer = jlib:nameprep(Server),
|
||||||
@ -299,14 +324,33 @@ migrate(After) ->
|
|||||||
['$$']}]),
|
['$$']}]),
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun([US, Pid]) ->
|
fun([US, Pid]) ->
|
||||||
case ejabberd_cluster:get_node_new(US) of
|
case ejabberd_cluster:get_node(US) of
|
||||||
Node when Node /= node() ->
|
Node when Node /= node() ->
|
||||||
ejabberd_c2s:migrate(Pid, Node, After);
|
ejabberd_c2s:migrate(Pid, Node, random:uniform(After));
|
||||||
_ ->
|
_ ->
|
||||||
ok
|
ok
|
||||||
end
|
end
|
||||||
end, Ss).
|
end, Ss).
|
||||||
|
|
||||||
|
node_up(_Node) ->
|
||||||
|
copy_sessions(mnesia:dirty_first(session)).
|
||||||
|
|
||||||
|
copy_sessions('$end_of_table') ->
|
||||||
|
ok;
|
||||||
|
copy_sessions(Key) ->
|
||||||
|
case mnesia:dirty_read(session, Key) of
|
||||||
|
[#session{us = US} = Session] ->
|
||||||
|
case ejabberd_cluster:get_node_new(US) of
|
||||||
|
Node when node() /= Node ->
|
||||||
|
rpc:cast(Node, mnesia, dirty_write, [Session]);
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
|
copy_sessions(mnesia:dirty_next(session, Key)).
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
@ -328,6 +372,7 @@ init([]) ->
|
|||||||
mnesia:add_table_index(session, us),
|
mnesia:add_table_index(session, us),
|
||||||
mnesia:add_table_copy(session, node(), ram_copies),
|
mnesia:add_table_copy(session, node(), ram_copies),
|
||||||
ets:new(sm_iqtable, [named_table]),
|
ets:new(sm_iqtable, [named_table]),
|
||||||
|
ejabberd_hooks:add(node_up, ?MODULE, node_up, 100),
|
||||||
ejabberd_hooks:add(node_hash_update, ?MODULE, migrate, 100),
|
ejabberd_hooks:add(node_hash_update, ?MODULE, migrate, 100),
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun(Host) ->
|
fun(Host) ->
|
||||||
@ -339,7 +384,7 @@ init([]) ->
|
|||||||
ejabberd_sm, disconnect_removed_user, 100)
|
ejabberd_sm, disconnect_removed_user, 100)
|
||||||
end, ?MYHOSTS),
|
end, ?MYHOSTS),
|
||||||
ejabberd_commands:register_commands(commands()),
|
ejabberd_commands:register_commands(commands()),
|
||||||
|
start_dispatchers(),
|
||||||
{ok, #state{}}.
|
{ok, #state{}}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
@ -370,13 +415,19 @@ handle_cast(_Msg, State) ->
|
|||||||
%% {stop, Reason, State}
|
%% {stop, Reason, State}
|
||||||
%% Description: Handling all non call/cast messages
|
%% Description: Handling all non call/cast messages
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
handle_info({route, From, To, Packet}, State) ->
|
handle_info({route, From, To, Packet} = Msg, State) ->
|
||||||
|
case get_proc_num() of
|
||||||
|
N when N > 1 ->
|
||||||
|
#jid{luser = U, lserver = S} = To,
|
||||||
|
get_proc_by_hash({U, S}) ! Msg;
|
||||||
|
_ ->
|
||||||
case catch do_route(From, To, Packet) of
|
case catch do_route(From, To, Packet) of
|
||||||
{'EXIT', Reason} ->
|
{'EXIT', Reason} ->
|
||||||
?ERROR_MSG("~p~nwhen processing: ~p",
|
?ERROR_MSG("~p~nwhen processing: ~p",
|
||||||
[Reason, {From, To, Packet}]);
|
[Reason, {From, To, Packet}]);
|
||||||
_ ->
|
_ ->
|
||||||
ok
|
ok
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
{noreply, State};
|
{noreply, State};
|
||||||
handle_info({register_iq_handler, Host, XMLNS, Module, Function}, State) ->
|
handle_info({register_iq_handler, Host, XMLNS, Module, Function}, State) ->
|
||||||
@ -405,8 +456,10 @@ handle_info(_Info, State) ->
|
|||||||
%% The return value is ignored.
|
%% The return value is ignored.
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
terminate(_Reason, _State) ->
|
terminate(_Reason, _State) ->
|
||||||
|
ejabberd_hooks:delete(node_up, ?MODULE, node_up, 100),
|
||||||
ejabberd_hooks:delete(node_hash_update, ?MODULE, migrate, 100),
|
ejabberd_hooks:delete(node_hash_update, ?MODULE, migrate, 100),
|
||||||
ejabberd_commands:unregister_commands(commands()),
|
ejabberd_commands:unregister_commands(commands()),
|
||||||
|
stop_dispatchers(),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
@ -420,7 +473,7 @@ code_change(_OldVsn, State, _Extra) ->
|
|||||||
%%% Internal functions
|
%%% Internal functions
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
set_session(SID, User, Server, Resource, Priority, Info) ->
|
set_session({_, Pid} = SID, User, Server, Resource, Priority, Info) ->
|
||||||
LUser = jlib:nodeprep(User),
|
LUser = jlib:nodeprep(User),
|
||||||
LServer = jlib:nameprep(Server),
|
LServer = jlib:nameprep(Server),
|
||||||
LResource = jlib:resourceprep(Resource),
|
LResource = jlib:resourceprep(Resource),
|
||||||
@ -433,7 +486,31 @@ set_session(SID, User, Server, Resource, Priority, Info) ->
|
|||||||
priority = Priority,
|
priority = Priority,
|
||||||
info = Info})
|
info = Info})
|
||||||
end,
|
end,
|
||||||
mnesia:sync_dirty(F).
|
mnesia:sync_dirty(F),
|
||||||
|
case ejabberd_cluster:get_node_new(US) of
|
||||||
|
Node when node() /= Node ->
|
||||||
|
%% New node has just been added. But we may miss session records
|
||||||
|
%% copy procedure, so we copy the session record manually just
|
||||||
|
%% to make sure
|
||||||
|
rpc:cast(Node, mnesia, dirty_write,
|
||||||
|
[#session{sid = SID,
|
||||||
|
usr = USR,
|
||||||
|
us = US,
|
||||||
|
priority = Priority,
|
||||||
|
info = Info}]),
|
||||||
|
case ejabberd_cluster:get_node(US) of
|
||||||
|
Node when node() /= Node ->
|
||||||
|
%% Migration to new node has completed, and seems like
|
||||||
|
%% we missed it, so we migrate the session pid manually.
|
||||||
|
%% It is not a problem if we have already got migration
|
||||||
|
%% notification: dups are just ignored by the c2s pid.
|
||||||
|
ejabberd_c2s:migrate(Pid, Node, 0);
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end.
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
@ -805,6 +882,55 @@ user_resources(User, Server) ->
|
|||||||
Resources = get_user_resources(User, Server),
|
Resources = get_user_resources(User, Server),
|
||||||
lists:sort(Resources).
|
lists:sort(Resources).
|
||||||
|
|
||||||
|
get_proc_num() ->
|
||||||
|
erlang:system_info(logical_processors).
|
||||||
|
|
||||||
|
get_proc_by_hash(Term) ->
|
||||||
|
N = erlang:phash2(Term, get_proc_num()) + 1,
|
||||||
|
get_proc(N).
|
||||||
|
|
||||||
|
get_proc(N) ->
|
||||||
|
list_to_atom(atom_to_list(?MODULE) ++ "_" ++ integer_to_list(N)).
|
||||||
|
|
||||||
|
start_dispatchers() ->
|
||||||
|
case get_proc_num() of
|
||||||
|
N when N > 1 ->
|
||||||
|
lists:foreach(
|
||||||
|
fun(I) ->
|
||||||
|
Pid = spawn(fun dispatch/0),
|
||||||
|
erlang:register(get_proc(I), Pid)
|
||||||
|
end, lists:seq(1, N));
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end.
|
||||||
|
|
||||||
|
stop_dispatchers() ->
|
||||||
|
case get_proc_num() of
|
||||||
|
N when N > 1 ->
|
||||||
|
lists:foreach(
|
||||||
|
fun(I) ->
|
||||||
|
get_proc(I) ! stop
|
||||||
|
end, lists:seq(1, N));
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end.
|
||||||
|
|
||||||
|
dispatch() ->
|
||||||
|
receive
|
||||||
|
{route, From, To, Packet} ->
|
||||||
|
case catch do_route(From, To, Packet) of
|
||||||
|
{'EXIT', Reason} ->
|
||||||
|
?ERROR_MSG("~p~nwhen processing: ~p",
|
||||||
|
[Reason, {From, To, Packet}]);
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
|
dispatch();
|
||||||
|
stop ->
|
||||||
|
stopped;
|
||||||
|
_ ->
|
||||||
|
dispatch()
|
||||||
|
end.
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
%%% Update Mnesia tables
|
%%% Update Mnesia tables
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 23 Aug 2006 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 23 Aug 2006 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% 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>
|
%%% Created : 31 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
@ -178,13 +178,6 @@ init([]) ->
|
|||||||
infinity,
|
infinity,
|
||||||
supervisor,
|
supervisor,
|
||||||
[ejabberd_tmp_sup]},
|
[ejabberd_tmp_sup]},
|
||||||
Cluster =
|
|
||||||
{ejabberd_cluster,
|
|
||||||
{ejabberd_cluster, start_link, []},
|
|
||||||
permanent,
|
|
||||||
brutal_kill,
|
|
||||||
worker,
|
|
||||||
[ejabberd_cluster]},
|
|
||||||
CacheTabSupervisor =
|
CacheTabSupervisor =
|
||||||
{cache_tab_sup,
|
{cache_tab_sup,
|
||||||
{cache_tab_sup, start_link, []},
|
{cache_tab_sup, start_link, []},
|
||||||
@ -194,7 +187,6 @@ init([]) ->
|
|||||||
[cache_tab_sup]},
|
[cache_tab_sup]},
|
||||||
{ok, {{one_for_one, 10, 1},
|
{ok, {{one_for_one, 10, 1},
|
||||||
[Hooks,
|
[Hooks,
|
||||||
Cluster,
|
|
||||||
SystemMonitor,
|
SystemMonitor,
|
||||||
Router,
|
Router,
|
||||||
SM,
|
SM,
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 21 Mar 2007 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 21 Mar 2007 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% 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>
|
%%% Created : 18 Jul 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 27 Jan 2006 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 27 Jan 2006 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 19 Jan 2006 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 19 Jan 2006 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% 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-2011 ProcessOne
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License as
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
@ -50,12 +50,23 @@
|
|||||||
#
|
#
|
||||||
#FIREWALL_WINDOW=
|
#FIREWALL_WINDOW=
|
||||||
|
|
||||||
|
#.
|
||||||
|
#' INET_DIST_INTERFACE: IP address where this Erlang node listens other nodes
|
||||||
|
#
|
||||||
|
# This communication is used by ejabberdctl command line tool,
|
||||||
|
# and in a cluster of several ejabberd nodes.
|
||||||
|
# Notice that the IP address must be specified in the Erlang syntax.
|
||||||
|
#
|
||||||
|
# Default: {127,0,0,1}
|
||||||
|
#
|
||||||
|
INET_DIST_INTERFACE={127,0,0,1}
|
||||||
|
|
||||||
#.
|
#.
|
||||||
#' ERL_PROCESSES: Maximum number of Erlang processes
|
#' ERL_PROCESSES: Maximum number of Erlang processes
|
||||||
#
|
#
|
||||||
# Erlang consumes a lot of lightweight processes. If there is a lot of activity
|
# 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
|
# on ejabberd so that the maximum number of processes is reached, people will
|
||||||
# experiment greater latency times. As these processes are implemented in
|
# experience greater latency times. As these processes are implemented in
|
||||||
# Erlang, and therefore not related to the operating system processes, you do
|
# Erlang, and therefore not related to the operating system processes, you do
|
||||||
# not have to worry about allowing a huge number of them.
|
# not have to worry about allowing a huge number of them.
|
||||||
#
|
#
|
||||||
|
@ -76,10 +76,12 @@ fi
|
|||||||
NAME=-name
|
NAME=-name
|
||||||
[ "$ERLANG_NODE" = "${ERLANG_NODE%.*}" ] && NAME=-sname
|
[ "$ERLANG_NODE" = "${ERLANG_NODE%.*}" ] && NAME=-sname
|
||||||
|
|
||||||
if [ "$FIREWALL_WINDOW" = "" ] ; then
|
|
||||||
KERNEL_OPTS=""
|
KERNEL_OPTS=""
|
||||||
else
|
if [ "$FIREWALL_WINDOW" != "" ] ; then
|
||||||
KERNEL_OPTS="-kernel inet_dist_listen_min ${FIREWALL_WINDOW%-*} inet_dist_listen_max ${FIREWALL_WINDOW#*-}"
|
KERNEL_OPTS="${KERNEL_OPTS} -kernel inet_dist_listen_min ${FIREWALL_WINDOW%-*} inet_dist_listen_max ${FIREWALL_WINDOW#*-}"
|
||||||
|
fi
|
||||||
|
if [ "$INET_DIST_INTERFACE" != "" ] ; then
|
||||||
|
KERNEL_OPTS="${KERNEL_OPTS} -kernel inet_dist_use_interface \"${INET_DIST_INTERFACE}\""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ERLANG_OPTS="+K $POLL -smp $SMP +P $ERL_PROCESSES $ERL_OPTIONS"
|
ERLANG_OPTS="+K $POLL -smp $SMP +P $ERL_PROCESSES $ERL_OPTIONS"
|
||||||
@ -321,13 +323,21 @@ ctlexec ()
|
|||||||
{
|
{
|
||||||
CONN_NAME=$1; shift
|
CONN_NAME=$1; shift
|
||||||
COMMAND=$@
|
COMMAND=$@
|
||||||
$EXEC_CMD "$ERL \
|
|
||||||
|
CTLEXEC="$ERL \
|
||||||
$NAME ${CONN_NAME} \
|
$NAME ${CONN_NAME} \
|
||||||
-noinput \
|
-noinput \
|
||||||
-hidden \
|
-hidden \
|
||||||
-pa $EJABBERD_EBIN_PATH \
|
-pa $EJABBERD_EBIN_PATH \
|
||||||
$KERNEL_OPTS \
|
$KERNEL_OPTS \
|
||||||
-s ejabberd_ctl -extra $ERLANG_NODE $COMMAND"
|
-s ejabberd_ctl -extra $ERLANG_NODE"
|
||||||
|
|
||||||
|
# quote input from the command line
|
||||||
|
for i in $COMMAND; do
|
||||||
|
CTLEXEC="$CTLEXEC '$i'";
|
||||||
|
done
|
||||||
|
|
||||||
|
$EXEC_CMD "$CTLEXEC"
|
||||||
}
|
}
|
||||||
|
|
||||||
# display ctl usage
|
# display ctl usage
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 22 Aug 2005 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 22 Aug 2005 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
%%% Author: Evgeniy Khramtsov <ekhramtsov@process-one.net>
|
%%% Author: Evgeniy Khramtsov <ekhramtsov@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 12 Nov 2006 by Evgeniy Khramtsov <xram@jabber.ru>
|
%%% Created : 12 Nov 2006 by Evgeniy Khramtsov <xram@jabber.ru>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 12 Oct 2006 by Mickael Remond <mremond@process-one.net>
|
%%% Created : 12 Oct 2006 by Mickael Remond <mremond@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% 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-2011 ProcessOne
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License as
|
* modify it under the terms of the GNU General Public License as
|
||||||
@ -35,6 +35,7 @@
|
|||||||
#define PARSE_FINAL_COMMAND 1
|
#define PARSE_FINAL_COMMAND 1
|
||||||
|
|
||||||
ei_x_buff event_buf;
|
ei_x_buff event_buf;
|
||||||
|
ei_x_buff xmlns_buf;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ErlDrvPort port;
|
ErlDrvPort port;
|
||||||
@ -43,6 +44,32 @@ typedef struct {
|
|||||||
|
|
||||||
static XML_Memory_Handling_Suite ms = {driver_alloc, driver_realloc, driver_free};
|
static XML_Memory_Handling_Suite ms = {driver_alloc, driver_realloc, driver_free};
|
||||||
|
|
||||||
|
void encode_name(const XML_Char *name)
|
||||||
|
{
|
||||||
|
char *name_start;
|
||||||
|
char *prefix_start;
|
||||||
|
char *buf;
|
||||||
|
int name_len, prefix_len, buf_len;
|
||||||
|
|
||||||
|
if ((name_start = strchr(name, '\n'))) {
|
||||||
|
if ((prefix_start = strchr(name_start+1, '\n'))) {
|
||||||
|
name_len = prefix_start - name_start;
|
||||||
|
prefix_len = strlen(prefix_start+1);
|
||||||
|
buf_len = prefix_len + name_len;
|
||||||
|
buf = driver_alloc(buf_len);
|
||||||
|
memcpy(buf, prefix_start+1, prefix_len);
|
||||||
|
memcpy(buf+prefix_len, name_start, name_len);
|
||||||
|
buf[prefix_len] = ':';
|
||||||
|
ei_x_encode_string_len(&event_buf, buf, buf_len);
|
||||||
|
driver_free(buf);
|
||||||
|
} else {
|
||||||
|
ei_x_encode_string(&event_buf, name_start+1);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
ei_x_encode_string(&event_buf, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void *erlXML_StartElementHandler(expat_data *d,
|
void *erlXML_StartElementHandler(expat_data *d,
|
||||||
const XML_Char *name,
|
const XML_Char *name,
|
||||||
const XML_Char **atts)
|
const XML_Char **atts)
|
||||||
@ -53,7 +80,10 @@ void *erlXML_StartElementHandler(expat_data *d,
|
|||||||
ei_x_encode_tuple_header(&event_buf, 2);
|
ei_x_encode_tuple_header(&event_buf, 2);
|
||||||
ei_x_encode_long(&event_buf, XML_START);
|
ei_x_encode_long(&event_buf, XML_START);
|
||||||
ei_x_encode_tuple_header(&event_buf, 2);
|
ei_x_encode_tuple_header(&event_buf, 2);
|
||||||
ei_x_encode_string(&event_buf, name);
|
encode_name(name);
|
||||||
|
ei_x_append(&event_buf, &xmlns_buf);
|
||||||
|
ei_x_free(&xmlns_buf);
|
||||||
|
ei_x_new(&xmlns_buf);
|
||||||
|
|
||||||
for (i = 0; atts[i]; i += 2) {}
|
for (i = 0; atts[i]; i += 2) {}
|
||||||
|
|
||||||
@ -64,7 +94,7 @@ void *erlXML_StartElementHandler(expat_data *d,
|
|||||||
for (i = 0; atts[i]; i += 2)
|
for (i = 0; atts[i]; i += 2)
|
||||||
{
|
{
|
||||||
ei_x_encode_tuple_header(&event_buf, 2);
|
ei_x_encode_tuple_header(&event_buf, 2);
|
||||||
ei_x_encode_string(&event_buf, atts[i]);
|
encode_name(atts[i]);
|
||||||
ei_x_encode_string(&event_buf, atts[i+1]);
|
ei_x_encode_string(&event_buf, atts[i+1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,7 +110,7 @@ void *erlXML_EndElementHandler(expat_data *d,
|
|||||||
ei_x_encode_list_header(&event_buf, 1);
|
ei_x_encode_list_header(&event_buf, 1);
|
||||||
ei_x_encode_tuple_header(&event_buf, 2);
|
ei_x_encode_tuple_header(&event_buf, 2);
|
||||||
ei_x_encode_long(&event_buf, XML_END);
|
ei_x_encode_long(&event_buf, XML_END);
|
||||||
ei_x_encode_string(&event_buf, name);
|
encode_name(name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,12 +125,45 @@ void *erlXML_CharacterDataHandler(expat_data *d,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *erlXML_StartNamespaceDeclHandler(expat_data *d,
|
||||||
|
const XML_Char *prefix,
|
||||||
|
const XML_Char *uri)
|
||||||
|
{
|
||||||
|
int prefix_len;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
/* From the expat documentation:
|
||||||
|
"For a default namespace declaration (xmlns='...'),
|
||||||
|
the prefix will be null ...
|
||||||
|
... The URI will be null for the case where
|
||||||
|
the default namespace is being unset."
|
||||||
|
|
||||||
|
FIXME: I'm not quite sure what all that means */
|
||||||
|
if (uri == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ei_x_encode_list_header(&xmlns_buf, 1);
|
||||||
|
ei_x_encode_tuple_header(&xmlns_buf, 2);
|
||||||
|
if (prefix) {
|
||||||
|
prefix_len = strlen(prefix);
|
||||||
|
buf = driver_alloc(7 + prefix_len);
|
||||||
|
strcpy(buf, "xmlns:");
|
||||||
|
strcpy(buf+6, prefix);
|
||||||
|
ei_x_encode_string(&xmlns_buf, buf);
|
||||||
|
driver_free(buf);
|
||||||
|
} else {
|
||||||
|
ei_x_encode_string(&xmlns_buf, "xmlns");
|
||||||
|
};
|
||||||
|
ei_x_encode_string(&xmlns_buf, uri);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static ErlDrvData expat_erl_start(ErlDrvPort port, char *buff)
|
static ErlDrvData expat_erl_start(ErlDrvPort port, char *buff)
|
||||||
{
|
{
|
||||||
expat_data* d = (expat_data*)driver_alloc(sizeof(expat_data));
|
expat_data* d = (expat_data*)driver_alloc(sizeof(expat_data));
|
||||||
d->port = port;
|
d->port = port;
|
||||||
d->parser = XML_ParserCreate_MM("UTF-8", &ms, NULL);
|
d->parser = XML_ParserCreate_MM("UTF-8", &ms, "\n");
|
||||||
XML_SetUserData(d->parser, d);
|
XML_SetUserData(d->parser, d);
|
||||||
|
|
||||||
set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY);
|
set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY);
|
||||||
@ -112,6 +175,11 @@ static ErlDrvData expat_erl_start(ErlDrvPort port, char *buff)
|
|||||||
XML_SetCharacterDataHandler(
|
XML_SetCharacterDataHandler(
|
||||||
d->parser, (XML_CharacterDataHandler)erlXML_CharacterDataHandler);
|
d->parser, (XML_CharacterDataHandler)erlXML_CharacterDataHandler);
|
||||||
|
|
||||||
|
XML_SetStartNamespaceDeclHandler(
|
||||||
|
d->parser, (XML_StartNamespaceDeclHandler) erlXML_StartNamespaceDeclHandler);
|
||||||
|
XML_SetReturnNSTriplet(d->parser, 1);
|
||||||
|
|
||||||
|
XML_SetDefaultHandler(d->parser, NULL);
|
||||||
|
|
||||||
return (ErlDrvData)d;
|
return (ErlDrvData)d;
|
||||||
}
|
}
|
||||||
@ -138,6 +206,7 @@ static int expat_erl_control(ErlDrvData drv_data,
|
|||||||
case PARSE_COMMAND:
|
case PARSE_COMMAND:
|
||||||
case PARSE_FINAL_COMMAND:
|
case PARSE_FINAL_COMMAND:
|
||||||
ei_x_new_with_version(&event_buf);
|
ei_x_new_with_version(&event_buf);
|
||||||
|
ei_x_new(&xmlns_buf);
|
||||||
#ifdef ENABLE_FLASH_HACK
|
#ifdef ENABLE_FLASH_HACK
|
||||||
/* Flash hack - Flash clients send a null byte after the stanza. Remove that... */
|
/* Flash hack - Flash clients send a null byte after the stanza. Remove that... */
|
||||||
{
|
{
|
||||||
@ -190,6 +259,7 @@ static int expat_erl_control(ErlDrvData drv_data,
|
|||||||
memcpy(b->orig_bytes, event_buf.buff, size);
|
memcpy(b->orig_bytes, event_buf.buff, size);
|
||||||
|
|
||||||
ei_x_free(&event_buf);
|
ei_x_free(&event_buf);
|
||||||
|
ei_x_free(&xmlns_buf);
|
||||||
|
|
||||||
*rbuf = (char *)b;
|
*rbuf = (char *)b;
|
||||||
return size;
|
return size;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 30 Jul 2004 by Leif Johansson <leifj@it.su.se>
|
%%% Created : 30 Jul 2004 by Leif Johansson <leifj@it.su.se>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
@ -45,16 +45,23 @@
|
|||||||
start(Host, ExtPrg) ->
|
start(Host, ExtPrg) ->
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun(This) ->
|
fun(This) ->
|
||||||
spawn(?MODULE, init, [get_process_name(Host, This), ExtPrg])
|
start_instance(get_process_name(Host, This), ExtPrg)
|
||||||
end,
|
end,
|
||||||
lists:seq(0, get_instances(Host)-1)
|
lists:seq(0, get_instances(Host)-1)
|
||||||
).
|
).
|
||||||
|
|
||||||
|
start_instance(ProcessName, ExtPrg) ->
|
||||||
|
spawn(?MODULE, init, [ProcessName, ExtPrg]).
|
||||||
|
|
||||||
|
restart_instance(ProcessName, ExtPrg) ->
|
||||||
|
unregister(ProcessName),
|
||||||
|
start_instance(ProcessName, ExtPrg).
|
||||||
|
|
||||||
init(ProcessName, ExtPrg) ->
|
init(ProcessName, ExtPrg) ->
|
||||||
register(ProcessName, self()),
|
register(ProcessName, self()),
|
||||||
process_flag(trap_exit,true),
|
process_flag(trap_exit,true),
|
||||||
Port = open_port({spawn, ExtPrg}, [{packet,2}]),
|
Port = open_port({spawn, ExtPrg}, [{packet,2}]),
|
||||||
loop(Port, ?INIT_TIMEOUT).
|
loop(Port, ?INIT_TIMEOUT, ProcessName, ExtPrg).
|
||||||
|
|
||||||
stop(Host) ->
|
stop(Host) ->
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
@ -108,23 +115,27 @@ get_instances(Server) ->
|
|||||||
_ -> 1
|
_ -> 1
|
||||||
end.
|
end.
|
||||||
|
|
||||||
loop(Port, Timeout) ->
|
loop(Port, Timeout, ProcessName, ExtPrg) ->
|
||||||
receive
|
receive
|
||||||
{call, Caller, Msg} ->
|
{call, Caller, Msg} ->
|
||||||
Port ! {self(), {command, encode(Msg)}},
|
port_command(Port, encode(Msg)),
|
||||||
receive
|
receive
|
||||||
{Port, {data, Data}} ->
|
{Port, {data, Data}} ->
|
||||||
?DEBUG("extauth call '~p' received data response:~n~p", [Msg, Data]),
|
?DEBUG("extauth call '~p' received data response:~n~p", [Msg, Data]),
|
||||||
Caller ! {eauth, decode(Data)};
|
Caller ! {eauth, decode(Data)},
|
||||||
|
loop(Port, ?CALL_TIMEOUT, ProcessName, ExtPrg);
|
||||||
{Port, Other} ->
|
{Port, Other} ->
|
||||||
?ERROR_MSG("extauth call '~p' received strange response:~n~p", [Msg, Other]),
|
?ERROR_MSG("extauth call '~p' received strange response:~n~p", [Msg, Other]),
|
||||||
Caller ! {eauth, false}
|
Caller ! {eauth, false},
|
||||||
|
loop(Port, ?CALL_TIMEOUT, ProcessName, ExtPrg)
|
||||||
after
|
after
|
||||||
Timeout ->
|
Timeout ->
|
||||||
?ERROR_MSG("extauth call '~p' didn't receive response", [Msg]),
|
?ERROR_MSG("extauth call '~p' didn't receive response", [Msg]),
|
||||||
Caller ! {eauth, false}
|
Caller ! {eauth, false},
|
||||||
end,
|
Pid = restart_instance(ProcessName, ExtPrg),
|
||||||
loop(Port, ?CALL_TIMEOUT);
|
flush_buffer_and_forward_messages(Pid),
|
||||||
|
exit(port_terminated)
|
||||||
|
end;
|
||||||
stop ->
|
stop ->
|
||||||
Port ! {self(), close},
|
Port ! {self(), close},
|
||||||
receive
|
receive
|
||||||
@ -132,10 +143,21 @@ loop(Port, Timeout) ->
|
|||||||
exit(normal)
|
exit(normal)
|
||||||
end;
|
end;
|
||||||
{'EXIT', Port, Reason} ->
|
{'EXIT', Port, Reason} ->
|
||||||
?CRITICAL_MSG("~p ~n", [Reason]),
|
?CRITICAL_MSG("extauth script has exitted abruptly with reason '~p'", [Reason]),
|
||||||
|
Pid = restart_instance(ProcessName, ExtPrg),
|
||||||
|
flush_buffer_and_forward_messages(Pid),
|
||||||
exit(port_terminated)
|
exit(port_terminated)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
flush_buffer_and_forward_messages(Pid) ->
|
||||||
|
receive
|
||||||
|
Message ->
|
||||||
|
Pid ! Message,
|
||||||
|
flush_buffer_and_forward_messages(Pid)
|
||||||
|
after 0 ->
|
||||||
|
true
|
||||||
|
end.
|
||||||
|
|
||||||
join(List, Sep) ->
|
join(List, Sep) ->
|
||||||
lists:foldl(fun(A, "") -> A;
|
lists:foldl(fun(A, "") -> A;
|
||||||
(A, Acc) -> Acc ++ Sep ++ A
|
(A, Acc) -> Acc ++ Sep ++ A
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 22 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 22 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 24 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 24 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
@ -70,11 +70,24 @@ start_module(Host, Module, Opts) ->
|
|||||||
catch Class:Reason ->
|
catch Class:Reason ->
|
||||||
del_module_mnesia(Host, Module),
|
del_module_mnesia(Host, Module),
|
||||||
ets:delete(ejabberd_modules, {Module, Host}),
|
ets:delete(ejabberd_modules, {Module, Host}),
|
||||||
?ERROR_MSG("Problem starting the module ~p for host ~p with options:~n ~p~n ~p: ~p",
|
ErrorText = io_lib:format("Problem starting the module ~p for host ~p ~n options: ~p~n ~p: ~p",
|
||||||
[Module, Host, Opts, Class, Reason]),
|
[Module, Host, Opts, Class, Reason]),
|
||||||
erlang:raise(Class, Reason, erlang:get_stacktrace())
|
?CRITICAL_MSG(ErrorText, []),
|
||||||
|
case is_app_running(ejabberd) of
|
||||||
|
true ->
|
||||||
|
erlang:raise(Class, Reason, erlang:get_stacktrace());
|
||||||
|
false ->
|
||||||
|
?CRITICAL_MSG("ejabberd initialization was aborted because a module start failed.", []),
|
||||||
|
timer:sleep(3000),
|
||||||
|
erlang:halt(lists:flatten(ErrorText))
|
||||||
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
is_app_running(AppName) ->
|
||||||
|
%% Use a high timeout to prevent a false positive in a high load system
|
||||||
|
Timeout = 15000,
|
||||||
|
lists:keymember(AppName, 1, application:which_applications(Timeout)).
|
||||||
|
|
||||||
%% @doc Stop the module in a host, and forget its configuration.
|
%% @doc Stop the module in a host, and forget its configuration.
|
||||||
stop_module(Host, Module) ->
|
stop_module(Host, Module) ->
|
||||||
case stop_module_keep_config(Host, Module) of
|
case stop_module_keep_config(Host, Module) of
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 10 Apr 2004 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 10 Apr 2004 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 2 Feb 2003 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 2 Feb 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 23 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 23 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
115
src/jlib.hrl
115
src/jlib.hrl
@ -1,6 +1,6 @@
|
|||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
@ -30,6 +30,7 @@
|
|||||||
-define(NS_ROSTER, "jabber:iq:roster").
|
-define(NS_ROSTER, "jabber:iq:roster").
|
||||||
-define(NS_ROSTER_VER, "urn:xmpp:features:rosterver").
|
-define(NS_ROSTER_VER, "urn:xmpp:features:rosterver").
|
||||||
-define(NS_PRIVACY, "jabber:iq:privacy").
|
-define(NS_PRIVACY, "jabber:iq:privacy").
|
||||||
|
-define(NS_BLOCKING, "urn:xmpp:blocking").
|
||||||
-define(NS_PRIVATE, "jabber:iq:private").
|
-define(NS_PRIVATE, "jabber:iq:private").
|
||||||
-define(NS_VERSION, "jabber:iq:version").
|
-define(NS_VERSION, "jabber:iq:version").
|
||||||
-define(NS_TIME90, "jabber:iq:time"). % TODO: Remove once XEP-0090 is Obsolete
|
-define(NS_TIME90, "jabber:iq:time"). % TODO: Remove once XEP-0090 is Obsolete
|
||||||
@ -206,117 +207,117 @@
|
|||||||
?ERRT_CONFLICT(Lang, "Resource conflict")).
|
?ERRT_CONFLICT(Lang, "Resource conflict")).
|
||||||
|
|
||||||
|
|
||||||
-define(STREAM_ERROR(Condition),
|
-define(STREAM_ERROR(Condition, Cdata),
|
||||||
{xmlelement, "stream:error",
|
{xmlelement, "stream:error",
|
||||||
[],
|
[],
|
||||||
[{xmlelement, Condition, [{"xmlns", ?NS_STREAMS}], []}]}).
|
[{xmlelement, Condition, [{"xmlns", ?NS_STREAMS}],
|
||||||
|
[{xmlcdata, Cdata}]}]}).
|
||||||
|
|
||||||
-define(SERR_BAD_FORMAT,
|
-define(SERR_BAD_FORMAT,
|
||||||
?STREAM_ERROR("bad-format")).
|
?STREAM_ERROR("bad-format", "")).
|
||||||
-define(SERR_BAD_NAMESPACE_PREFIX,
|
-define(SERR_BAD_NAMESPACE_PREFIX,
|
||||||
?STREAM_ERROR("bad-namespace-prefix")).
|
?STREAM_ERROR("bad-namespace-prefix", "")).
|
||||||
-define(SERR_CONFLICT,
|
-define(SERR_CONFLICT,
|
||||||
?STREAM_ERROR("conflict")).
|
?STREAM_ERROR("conflict", "")).
|
||||||
-define(SERR_CONNECTION_TIMEOUT,
|
-define(SERR_CONNECTION_TIMEOUT,
|
||||||
?STREAM_ERROR("connection-timeout")).
|
?STREAM_ERROR("connection-timeout", "")).
|
||||||
-define(SERR_HOST_GONE,
|
-define(SERR_HOST_GONE,
|
||||||
?STREAM_ERROR("host-gone")).
|
?STREAM_ERROR("host-gone", "")).
|
||||||
-define(SERR_HOST_UNKNOWN,
|
-define(SERR_HOST_UNKNOWN,
|
||||||
?STREAM_ERROR("host-unknown")).
|
?STREAM_ERROR("host-unknown", "")).
|
||||||
-define(SERR_IMPROPER_ADDRESSING,
|
-define(SERR_IMPROPER_ADDRESSING,
|
||||||
?STREAM_ERROR("improper-addressing")).
|
?STREAM_ERROR("improper-addressing", "")).
|
||||||
-define(SERR_INTERNAL_SERVER_ERROR,
|
-define(SERR_INTERNAL_SERVER_ERROR,
|
||||||
?STREAM_ERROR("internal-server-error")).
|
?STREAM_ERROR("internal-server-error", "")).
|
||||||
-define(SERR_INVALID_FROM,
|
-define(SERR_INVALID_FROM,
|
||||||
?STREAM_ERROR("invalid-from")).
|
?STREAM_ERROR("invalid-from", "")).
|
||||||
-define(SERR_INVALID_ID,
|
-define(SERR_INVALID_ID,
|
||||||
?STREAM_ERROR("invalid-id")).
|
?STREAM_ERROR("invalid-id", "")).
|
||||||
-define(SERR_INVALID_NAMESPACE,
|
-define(SERR_INVALID_NAMESPACE,
|
||||||
?STREAM_ERROR("invalid-namespace")).
|
?STREAM_ERROR("invalid-namespace", "")).
|
||||||
-define(SERR_INVALID_XML,
|
-define(SERR_INVALID_XML,
|
||||||
?STREAM_ERROR("invalid-xml")).
|
?STREAM_ERROR("invalid-xml", "")).
|
||||||
-define(SERR_NOT_AUTHORIZED,
|
-define(SERR_NOT_AUTHORIZED,
|
||||||
?STREAM_ERROR("not-authorized")).
|
?STREAM_ERROR("not-authorized", "")).
|
||||||
-define(SERR_POLICY_VIOLATION,
|
-define(SERR_POLICY_VIOLATION,
|
||||||
?STREAM_ERROR("policy-violation")).
|
?STREAM_ERROR("policy-violation", "")).
|
||||||
-define(SERR_REMOTE_CONNECTION_FAILED,
|
-define(SERR_REMOTE_CONNECTION_FAILED,
|
||||||
?STREAM_ERROR("remote-connection-failed")).
|
?STREAM_ERROR("remote-connection-failed", "")).
|
||||||
-define(SERR_RESOURSE_CONSTRAINT,
|
-define(SERR_RESOURSE_CONSTRAINT,
|
||||||
?STREAM_ERROR("resource-constraint")).
|
?STREAM_ERROR("resource-constraint", "")).
|
||||||
-define(SERR_RESTRICTED_XML,
|
-define(SERR_RESTRICTED_XML,
|
||||||
?STREAM_ERROR("restricted-xml")).
|
?STREAM_ERROR("restricted-xml", "")).
|
||||||
% TODO: include hostname or IP
|
-define(SERR_SEE_OTHER_HOST(Host),
|
||||||
-define(SERR_SEE_OTHER_HOST,
|
?STREAM_ERROR("see-other-host", Host)).
|
||||||
?STREAM_ERROR("see-other-host")).
|
|
||||||
-define(SERR_SYSTEM_SHUTDOWN,
|
-define(SERR_SYSTEM_SHUTDOWN,
|
||||||
?STREAM_ERROR("system-shutdown")).
|
?STREAM_ERROR("system-shutdown", "")).
|
||||||
-define(SERR_UNSUPPORTED_ENCODING,
|
-define(SERR_UNSUPPORTED_ENCODING,
|
||||||
?STREAM_ERROR("unsupported-encoding")).
|
?STREAM_ERROR("unsupported-encoding", "")).
|
||||||
-define(SERR_UNSUPPORTED_STANZA_TYPE,
|
-define(SERR_UNSUPPORTED_STANZA_TYPE,
|
||||||
?STREAM_ERROR("unsupported-stanza-type")).
|
?STREAM_ERROR("unsupported-stanza-type", "")).
|
||||||
-define(SERR_UNSUPPORTED_VERSION,
|
-define(SERR_UNSUPPORTED_VERSION,
|
||||||
?STREAM_ERROR("unsupported-version")).
|
?STREAM_ERROR("unsupported-version", "")).
|
||||||
-define(SERR_XML_NOT_WELL_FORMED,
|
-define(SERR_XML_NOT_WELL_FORMED,
|
||||||
?STREAM_ERROR("xml-not-well-formed")).
|
?STREAM_ERROR("xml-not-well-formed", "")).
|
||||||
%-define(SERR_,
|
%-define(SERR_,
|
||||||
% ?STREAM_ERROR("")).
|
% ?STREAM_ERROR("", "")).
|
||||||
|
|
||||||
-define(STREAM_ERRORT(Condition, Lang, Text),
|
-define(STREAM_ERRORT(Condition, Cdata, Lang, Text),
|
||||||
{xmlelement, "stream:error",
|
{xmlelement, "stream:error",
|
||||||
[],
|
[],
|
||||||
[{xmlelement, Condition, [{"xmlns", ?NS_STREAMS}], []},
|
[{xmlelement, Condition, [{"xmlns", ?NS_STREAMS}],
|
||||||
|
[{xmlcdata, Cdata}]},
|
||||||
{xmlelement, "text", [{"xml:lang", Lang}, {"xmlns", ?NS_STREAMS}],
|
{xmlelement, "text", [{"xml:lang", Lang}, {"xmlns", ?NS_STREAMS}],
|
||||||
[{xmlcdata, translate:translate(Lang, Text)}]}]}).
|
[{xmlcdata, translate:translate(Lang, Text)}]}]}).
|
||||||
|
|
||||||
-define(SERRT_BAD_FORMAT(Lang, Text),
|
-define(SERRT_BAD_FORMAT(Lang, Text),
|
||||||
?STREAM_ERRORT("bad-format", Lang, Text)).
|
?STREAM_ERRORT("bad-format", "", Lang, Text)).
|
||||||
-define(SERRT_BAD_NAMESPACE_PREFIX(Lang, Text),
|
-define(SERRT_BAD_NAMESPACE_PREFIX(Lang, Text),
|
||||||
?STREAM_ERRORT("bad-namespace-prefix", Lang, Text)).
|
?STREAM_ERRORT("bad-namespace-prefix", "", Lang, Text)).
|
||||||
-define(SERRT_CONFLICT(Lang, Text),
|
-define(SERRT_CONFLICT(Lang, Text),
|
||||||
?STREAM_ERRORT("conflict", Lang, Text)).
|
?STREAM_ERRORT("conflict", "", Lang, Text)).
|
||||||
-define(SERRT_CONNECTION_TIMEOUT(Lang, Text),
|
-define(SERRT_CONNECTION_TIMEOUT(Lang, Text),
|
||||||
?STREAM_ERRORT("connection-timeout", Lang, Text)).
|
?STREAM_ERRORT("connection-timeout", "", Lang, Text)).
|
||||||
-define(SERRT_HOST_GONE(Lang, Text),
|
-define(SERRT_HOST_GONE(Lang, Text),
|
||||||
?STREAM_ERRORT("host-gone", Lang, Text)).
|
?STREAM_ERRORT("host-gone", "", Lang, Text)).
|
||||||
-define(SERRT_HOST_UNKNOWN(Lang, Text),
|
-define(SERRT_HOST_UNKNOWN(Lang, Text),
|
||||||
?STREAM_ERRORT("host-unknown", Lang, Text)).
|
?STREAM_ERRORT("host-unknown", "", Lang, Text)).
|
||||||
-define(SERRT_IMPROPER_ADDRESSING(Lang, Text),
|
-define(SERRT_IMPROPER_ADDRESSING(Lang, Text),
|
||||||
?STREAM_ERRORT("improper-addressing", Lang, Text)).
|
?STREAM_ERRORT("improper-addressing", "", Lang, Text)).
|
||||||
-define(SERRT_INTERNAL_SERVER_ERROR(Lang, Text),
|
-define(SERRT_INTERNAL_SERVER_ERROR(Lang, Text),
|
||||||
?STREAM_ERRORT("internal-server-error", Lang, Text)).
|
?STREAM_ERRORT("internal-server-error", "", Lang, Text)).
|
||||||
-define(SERRT_INVALID_FROM(Lang, Text),
|
-define(SERRT_INVALID_FROM(Lang, Text),
|
||||||
?STREAM_ERRORT("invalid-from", Lang, Text)).
|
?STREAM_ERRORT("invalid-from", "", Lang, Text)).
|
||||||
-define(SERRT_INVALID_ID(Lang, Text),
|
-define(SERRT_INVALID_ID(Lang, Text),
|
||||||
?STREAM_ERRORT("invalid-id", Lang, Text)).
|
?STREAM_ERRORT("invalid-id", "", Lang, Text)).
|
||||||
-define(SERRT_INVALID_NAMESPACE(Lang, Text),
|
-define(SERRT_INVALID_NAMESPACE(Lang, Text),
|
||||||
?STREAM_ERRORT("invalid-namespace", Lang, Text)).
|
?STREAM_ERRORT("invalid-namespace", "", Lang, Text)).
|
||||||
-define(SERRT_INVALID_XML(Lang, Text),
|
-define(SERRT_INVALID_XML(Lang, Text),
|
||||||
?STREAM_ERRORT("invalid-xml", Lang, Text)).
|
?STREAM_ERRORT("invalid-xml", "", Lang, Text)).
|
||||||
-define(SERRT_NOT_AUTHORIZED(Lang, Text),
|
-define(SERRT_NOT_AUTHORIZED(Lang, Text),
|
||||||
?STREAM_ERRORT("not-authorized", Lang, Text)).
|
?STREAM_ERRORT("not-authorized", "", Lang, Text)).
|
||||||
-define(SERRT_POLICY_VIOLATION(Lang, Text),
|
-define(SERRT_POLICY_VIOLATION(Lang, Text),
|
||||||
?STREAM_ERRORT("policy-violation", Lang, Text)).
|
?STREAM_ERRORT("policy-violation", "", Lang, Text)).
|
||||||
-define(SERRT_REMOTE_CONNECTION_FAILED(Lang, Text),
|
-define(SERRT_REMOTE_CONNECTION_FAILED(Lang, Text),
|
||||||
?STREAM_ERRORT("remote-connection-failed", Lang, Text)).
|
?STREAM_ERRORT("remote-connection-failed", "", Lang, Text)).
|
||||||
-define(SERRT_RESOURSE_CONSTRAINT(Lang, Text),
|
-define(SERRT_RESOURSE_CONSTRAINT(Lang, Text),
|
||||||
?STREAM_ERRORT("resource-constraint", Lang, Text)).
|
?STREAM_ERRORT("resource-constraint", "", Lang, Text)).
|
||||||
-define(SERRT_RESTRICTED_XML(Lang, Text),
|
-define(SERRT_RESTRICTED_XML(Lang, Text),
|
||||||
?STREAM_ERRORT("restricted-xml", Lang, Text)).
|
?STREAM_ERRORT("restricted-xml", "", Lang, Text)).
|
||||||
% TODO: include hostname or IP
|
-define(SERRT_SEE_OTHER_HOST(Host, Lang, Text),
|
||||||
-define(SERRT_SEE_OTHER_HOST(Lang, Text),
|
?STREAM_ERRORT("see-other-host", Host, Lang, Text)).
|
||||||
?STREAM_ERRORT("see-other-host", Lang, Text)).
|
|
||||||
-define(SERRT_SYSTEM_SHUTDOWN(Lang, Text),
|
-define(SERRT_SYSTEM_SHUTDOWN(Lang, Text),
|
||||||
?STREAM_ERRORT("system-shutdown", Lang, Text)).
|
?STREAM_ERRORT("system-shutdown", "", Lang, Text)).
|
||||||
-define(SERRT_UNSUPPORTED_ENCODING(Lang, Text),
|
-define(SERRT_UNSUPPORTED_ENCODING(Lang, Text),
|
||||||
?STREAM_ERRORT("unsupported-encoding", Lang, Text)).
|
?STREAM_ERRORT("unsupported-encoding", "", Lang, Text)).
|
||||||
-define(SERRT_UNSUPPORTED_STANZA_TYPE(Lang, Text),
|
-define(SERRT_UNSUPPORTED_STANZA_TYPE(Lang, Text),
|
||||||
?STREAM_ERRORT("unsupported-stanza-type", Lang, Text)).
|
?STREAM_ERRORT("unsupported-stanza-type", "", Lang, Text)).
|
||||||
-define(SERRT_UNSUPPORTED_VERSION(Lang, Text),
|
-define(SERRT_UNSUPPORTED_VERSION(Lang, Text),
|
||||||
?STREAM_ERRORT("unsupported-version", Lang, Text)).
|
?STREAM_ERRORT("unsupported-version", "", Lang, Text)).
|
||||||
-define(SERRT_XML_NOT_WELL_FORMED(Lang, Text),
|
-define(SERRT_XML_NOT_WELL_FORMED(Lang, Text),
|
||||||
?STREAM_ERRORT("xml-not-well-formed", Lang, Text)).
|
?STREAM_ERRORT("xml-not-well-formed", "", Lang, Text)).
|
||||||
%-define(SERRT_(Lang, Text),
|
%-define(SERRT_(Lang, Text),
|
||||||
% ?STREAM_ERRORT("", Lang, Text)).
|
% ?STREAM_ERRORT("", "", Lang, Text)).
|
||||||
|
|
||||||
|
|
||||||
-record(jid, {user, server, resource,
|
-record(jid, {user, server, resource,
|
||||||
|
420
src/mod_ack.erl
Normal file
420
src/mod_ack.erl
Normal file
@ -0,0 +1,420 @@
|
|||||||
|
%%%-------------------------------------------------------------------
|
||||||
|
%%% File : mod_ack.erl
|
||||||
|
%%% Author : Mickael Remond <mremond@process-one.net>
|
||||||
|
%%% Description : Implements reliable message delivery
|
||||||
|
%%% Note: this module depends on mod_caps
|
||||||
|
%%% Created : 12 Mar 2010 by Mickael Remond <mremond@process-one.net>
|
||||||
|
%%%
|
||||||
|
%%%
|
||||||
|
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
||||||
|
%%%
|
||||||
|
%%% This program is free software; you can redistribute it and/or
|
||||||
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
%%% published by the Free Software Foundation; either version 2 of the
|
||||||
|
%%% License, or (at your option) any later version.
|
||||||
|
%%%
|
||||||
|
%%% This program is distributed in the hope that it will be useful,
|
||||||
|
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
%%% General Public License for more details.
|
||||||
|
%%%
|
||||||
|
%%% You should have received a copy of the GNU General Public License
|
||||||
|
%%% along with this program; if not, write to the Free Software
|
||||||
|
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
|
%%% 02111-1307 USA
|
||||||
|
%%%
|
||||||
|
%%%-------------------------------------------------------------------
|
||||||
|
-module(mod_ack).
|
||||||
|
|
||||||
|
-behaviour(gen_server).
|
||||||
|
-behaviour(gen_mod).
|
||||||
|
|
||||||
|
%% API
|
||||||
|
-export([start/2, stop/1, start_link/2]).
|
||||||
|
|
||||||
|
-export([user_send_packet/3,
|
||||||
|
offline_message/3,
|
||||||
|
delayed_message/3,
|
||||||
|
remove_connection/3,
|
||||||
|
feature_inspect_packet/4]).
|
||||||
|
|
||||||
|
%% gen_server callbacks
|
||||||
|
-export([init/1,
|
||||||
|
handle_info/2,
|
||||||
|
handle_call/3,
|
||||||
|
handle_cast/2,
|
||||||
|
terminate/2,
|
||||||
|
code_change/3]).
|
||||||
|
|
||||||
|
-include("jlib.hrl").
|
||||||
|
-include("ejabberd.hrl").
|
||||||
|
|
||||||
|
-define(PROCNAME, ejabberd_mod_ack).
|
||||||
|
-define(ACK_TIMEOUT, 60). %% seconds
|
||||||
|
-define(DICT, dict).
|
||||||
|
|
||||||
|
-ifndef(NS_RECEIPTS).
|
||||||
|
-define(NS_RECEIPTS, "urn:xmpp:receipts").
|
||||||
|
-endif.
|
||||||
|
-ifndef(NS_PING).
|
||||||
|
-define(NS_PING, "urn:xmpp:ping").
|
||||||
|
-endif.
|
||||||
|
-ifndef(NS_P1_PUSHED).
|
||||||
|
-define(NS_P1_PUSHED, "p1:pushed").
|
||||||
|
-endif.
|
||||||
|
|
||||||
|
-record(state, {host, timers = ?DICT:new(), timeout}).
|
||||||
|
|
||||||
|
%%====================================================================
|
||||||
|
%% API
|
||||||
|
%%====================================================================
|
||||||
|
start_link(Host, Opts) ->
|
||||||
|
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||||
|
gen_server:start_link({local, Proc}, ?MODULE, [Host, Opts], []).
|
||||||
|
|
||||||
|
start(Host, Opts) ->
|
||||||
|
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||||
|
ChildSpec =
|
||||||
|
{Proc,
|
||||||
|
{?MODULE, start_link, [Host, Opts]},
|
||||||
|
transient,
|
||||||
|
1000,
|
||||||
|
worker,
|
||||||
|
[?MODULE]},
|
||||||
|
supervisor:start_child(ejabberd_sup, ChildSpec).
|
||||||
|
|
||||||
|
stop(Host) ->
|
||||||
|
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||||
|
gen_server:call(Proc, stop),
|
||||||
|
supervisor:terminate_child(ejabberd_sup, Proc),
|
||||||
|
supervisor:delete_child(ejabberd_sup, Proc).
|
||||||
|
|
||||||
|
%% TODO: Make ack on server receive optional ?
|
||||||
|
user_send_packet(From, To, {xmlelement, "message", _Attrs, _Els} = Packet) ->
|
||||||
|
case has_receipt_request(Packet) of
|
||||||
|
{true, _} ->
|
||||||
|
process_ack_request("on-sender-server", From, To, Packet);
|
||||||
|
false ->
|
||||||
|
case has_receipt_response(Packet) of
|
||||||
|
{true, ID} ->
|
||||||
|
Server = From#jid.lserver,
|
||||||
|
del_timer(Server, {message, ID}, From);
|
||||||
|
false ->
|
||||||
|
do_nothing
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
user_send_packet(From, _To, {xmlelement, "iq", Attrs, _Els}) ->
|
||||||
|
case xml:get_attr_s("id", Attrs) of
|
||||||
|
"" ->
|
||||||
|
ok;
|
||||||
|
ID ->
|
||||||
|
Server = From#jid.lserver,
|
||||||
|
del_timer(Server, {iq, ID}, From)
|
||||||
|
end;
|
||||||
|
user_send_packet(_From, _To, _Packet) ->
|
||||||
|
do_nothing.
|
||||||
|
|
||||||
|
offline_message(From, To, Packet) ->
|
||||||
|
process_ack_request("offline", From, To, Packet),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
delayed_message(From, To, Packet) ->
|
||||||
|
process_ack_request("delayed", From, To, Packet),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
feature_inspect_packet(JID, Server,
|
||||||
|
{xmlelement, "presence", _, _} = Pres,
|
||||||
|
{xmlelement, "message", Attrs, _} = El) ->
|
||||||
|
HasReceipts = has_receipt_request(El),
|
||||||
|
ReceiptsSupported = are_receipts_supported(Pres),
|
||||||
|
?DEBUG("feature_inspect_packet:~n"
|
||||||
|
"** JID: ~p~n"
|
||||||
|
"** Has receipts: ~p~n"
|
||||||
|
"** Receipts supported: ~p~n"
|
||||||
|
"** Pres: ~p~n"
|
||||||
|
"** El: ~p",
|
||||||
|
[JID, HasReceipts, ReceiptsSupported, Pres, El]),
|
||||||
|
Type = xml:get_attr_s("type", Attrs),
|
||||||
|
case HasReceipts of
|
||||||
|
_ when Type == "error" ->
|
||||||
|
ok;
|
||||||
|
{true, ID} ->
|
||||||
|
case {jlib:string_to_jid(xml:get_attr_s("from", Attrs)),
|
||||||
|
jlib:string_to_jid(xml:get_attr_s("to", Attrs))} of
|
||||||
|
{#jid{} = From, #jid{} = To} ->
|
||||||
|
Pkt = {From, To, El},
|
||||||
|
case ReceiptsSupported of
|
||||||
|
true ->
|
||||||
|
add_timer(Server, {message, ID}, JID, Pkt);
|
||||||
|
false ->
|
||||||
|
ping(From, To, Server, JID, El);
|
||||||
|
unknown ->
|
||||||
|
process_ack_request("unreliable", From, To, El)
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
?WARNING_MSG("message doesn't have 'from' or 'to'"
|
||||||
|
" attribute:~n** El: ~p", [El])
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end;
|
||||||
|
feature_inspect_packet(_User, _Server, _Pres, _El) ->
|
||||||
|
ok.
|
||||||
|
|
||||||
|
remove_connection({_, C2SPid}, #jid{lserver = Host}, _Info) ->
|
||||||
|
gen_server:cast(gen_mod:get_module_proc(Host, ?PROCNAME), {del, C2SPid}).
|
||||||
|
|
||||||
|
%%====================================================================
|
||||||
|
%% gen_server callbacks
|
||||||
|
%%====================================================================
|
||||||
|
init([Host, Opts]) ->
|
||||||
|
Timeout = timer:seconds(gen_mod:get_opt(timeout, Opts, ?ACK_TIMEOUT)),
|
||||||
|
ejabberd_hooks:add(user_send_packet, Host,
|
||||||
|
?MODULE, user_send_packet, 20),
|
||||||
|
ejabberd_hooks:add(offline_message_hook, Host,
|
||||||
|
?MODULE, offline_message, 20),
|
||||||
|
ejabberd_hooks:add(delayed_message_hook, Host,
|
||||||
|
?MODULE, delayed_message, 20),
|
||||||
|
ejabberd_hooks:add(feature_inspect_packet, Host,
|
||||||
|
?MODULE, feature_inspect_packet, 150),
|
||||||
|
ejabberd_hooks:add(sm_remove_connection_hook, Host,
|
||||||
|
?MODULE, remove_connection, 20),
|
||||||
|
ejabberd_hooks:add(sm_remove_migrated_connection_hook, Host,
|
||||||
|
?MODULE, remove_connection, 20),
|
||||||
|
{ok, #state{host = Host, timeout = Timeout}}.
|
||||||
|
|
||||||
|
handle_call(stop, _From, State) ->
|
||||||
|
{stop, normal, ok, State};
|
||||||
|
handle_call(_Req, _From, State) ->
|
||||||
|
{reply, {error, badarg}, State}.
|
||||||
|
|
||||||
|
handle_cast({add, ID, Pid, Packet}, State) ->
|
||||||
|
TRef = erlang:start_timer(State#state.timeout, self(), {ID, Pid}),
|
||||||
|
Timers = insert(Pid, ID, {TRef, Packet}, State#state.timers),
|
||||||
|
{noreply, State#state{timers = Timers}};
|
||||||
|
handle_cast({del, ID, Pid}, State) ->
|
||||||
|
case lookup(Pid, ID, State#state.timers) of
|
||||||
|
{ok, {TRef, {From, To, {xmlelement, _, Attrs, _}}}} ->
|
||||||
|
cancel_timer(TRef),
|
||||||
|
Timers = delete(Pid, ID, State#state.timers),
|
||||||
|
case ID of
|
||||||
|
{iq, _} ->
|
||||||
|
MsgID = xml:get_attr_s("id", Attrs),
|
||||||
|
Message = {xmlelement, "message", [{"id", MsgID}],
|
||||||
|
[{xmlelement, "received",
|
||||||
|
[{"xmlns", ?NS_RECEIPTS}, {"id", MsgID}], []}]},
|
||||||
|
ejabberd_router:route(To, From, Message);
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
|
{noreply, State#state{timers = Timers}};
|
||||||
|
error ->
|
||||||
|
{noreply, State}
|
||||||
|
end;
|
||||||
|
handle_cast({del, Pid}, State) ->
|
||||||
|
lists:foreach(
|
||||||
|
fun({_, _, {TRef, {From, To, El}}}) ->
|
||||||
|
cancel_timer(TRef),
|
||||||
|
El1 = xml:remove_subtags(El, "x", {"xmlns", ?NS_P1_PUSHED}),
|
||||||
|
El2 = xml:append_subtags(
|
||||||
|
El1, [{xmlelement, "x", [{"xmlns", ?NS_P1_PUSHED}], []}]),
|
||||||
|
?DEBUG("Resending message:~n"
|
||||||
|
"** From: ~p~n"
|
||||||
|
"** To: ~p~n"
|
||||||
|
"** El: ~p",
|
||||||
|
[From, To, El2]),
|
||||||
|
ejabberd_router:route(From, To, El2)
|
||||||
|
end, to_list(Pid, State#state.timers)),
|
||||||
|
Timers = delete(Pid, State#state.timers),
|
||||||
|
{noreply, State#state{timers = Timers}};
|
||||||
|
handle_cast(_Msg, State) ->
|
||||||
|
{noreply, State}.
|
||||||
|
|
||||||
|
handle_info({timeout, _TRef, {ID, Pid}}, State) ->
|
||||||
|
case lookup(Pid, ID, State#state.timers) of
|
||||||
|
{ok, _} ->
|
||||||
|
MRef = erlang:monitor(process, Pid),
|
||||||
|
catch ejabberd_c2s:stop(Pid),
|
||||||
|
receive
|
||||||
|
{'DOWN', MRef, process, Pid, _Reason}->
|
||||||
|
ok
|
||||||
|
after 5 ->
|
||||||
|
catch exit(Pid, kill)
|
||||||
|
end,
|
||||||
|
erlang:demonitor(MRef, [flush]),
|
||||||
|
handle_cast({del, Pid}, State);
|
||||||
|
error ->
|
||||||
|
{noreply, State}
|
||||||
|
end;
|
||||||
|
handle_info(_Info, State) ->
|
||||||
|
{noreply, State}.
|
||||||
|
|
||||||
|
terminate(_Reason, State) ->
|
||||||
|
Host = State#state.host,
|
||||||
|
ejabberd_hooks:delete(user_send_packet, Host,
|
||||||
|
?MODULE, user_send_packet, 20),
|
||||||
|
ejabberd_hooks:delete(offline_message_hook, Host,
|
||||||
|
?MODULE, offline_message, 20),
|
||||||
|
ejabberd_hooks:delete(delayed_message_hook, Host,
|
||||||
|
?MODULE, delayed_message, 20),
|
||||||
|
ejabberd_hooks:delete(feature_inspect_packet, Host,
|
||||||
|
?MODULE, feature_inspect_packet, 150),
|
||||||
|
ejabberd_hooks:delete(sm_remove_connection_hook, Host,
|
||||||
|
?MODULE, remove_connection, 20),
|
||||||
|
ejabberd_hooks:delete(sm_remove_migrated_connection_hook, Host,
|
||||||
|
?MODULE, remove_connection, 20),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
code_change(_OldVsn, State, _Extra) ->
|
||||||
|
{ok, State}.
|
||||||
|
|
||||||
|
%%====================================================================
|
||||||
|
%% Internal functions
|
||||||
|
%%====================================================================
|
||||||
|
process_ack_request(AckTagName,
|
||||||
|
#jid{lserver=LServer} = From, To,
|
||||||
|
{xmlelement, "message", _Attrs, _Els} = Packet) ->
|
||||||
|
case has_receipt_request(Packet) of
|
||||||
|
{true, ID} ->
|
||||||
|
BareTo = jlib:jid_remove_resource(To),
|
||||||
|
Message = {xmlelement, "message", [{"id", ID}],
|
||||||
|
[{xmlelement, AckTagName,
|
||||||
|
[{"xmlns", ?NS_RECEIPTS},
|
||||||
|
{"server", LServer}, {"id", ID}], []}]},
|
||||||
|
ejabberd_router:route(BareTo, From, Message);
|
||||||
|
false ->
|
||||||
|
do_nothing
|
||||||
|
end.
|
||||||
|
|
||||||
|
has_receipt_request(Packet) ->
|
||||||
|
has_receipt(Packet, "request").
|
||||||
|
|
||||||
|
has_receipt_response(Packet) ->
|
||||||
|
has_receipt(Packet, "received").
|
||||||
|
|
||||||
|
has_receipt({xmlelement, "message", MsgAttrs, _} = Packet, Type) ->
|
||||||
|
case xml:get_attr_s("id", MsgAttrs) of
|
||||||
|
"" ->
|
||||||
|
case Type of
|
||||||
|
"request" -> false; %% Message must have an ID to ask a request for ack.
|
||||||
|
"received" ->
|
||||||
|
case xml:get_subtag(Packet, "received") of
|
||||||
|
false ->
|
||||||
|
false;
|
||||||
|
{xmlelement, _Name, Attrs, _Els} ->
|
||||||
|
case xml:get_attr_s("xmlns", Attrs) of
|
||||||
|
?NS_RECEIPTS ->
|
||||||
|
case xml:get_attr_s("id", Attrs) of
|
||||||
|
"" -> false;
|
||||||
|
SubTagID -> {true, SubTagID}
|
||||||
|
end;
|
||||||
|
_ -> false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
ID ->
|
||||||
|
case xml:get_subtag(Packet, Type) of
|
||||||
|
false ->
|
||||||
|
false;
|
||||||
|
{xmlelement, _Name, Attrs, _Els} ->
|
||||||
|
case xml:get_attr_s("xmlns", Attrs) of
|
||||||
|
?NS_RECEIPTS ->
|
||||||
|
case xml:get_attr_s("id", Attrs) of
|
||||||
|
"" -> {true, ID};
|
||||||
|
SubTagID -> {true, SubTagID}
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
|
are_receipts_supported(undefined) ->
|
||||||
|
unknown;
|
||||||
|
are_receipts_supported({xmlelement, "presence", _, Els}) ->
|
||||||
|
case mod_caps:read_caps(Els) of
|
||||||
|
nothing ->
|
||||||
|
unknown;
|
||||||
|
Caps ->
|
||||||
|
lists:member(?NS_RECEIPTS, mod_caps:get_features(Caps))
|
||||||
|
end.
|
||||||
|
|
||||||
|
ping(From, To, Server, JID, El) ->
|
||||||
|
ID = randoms:get_string(),
|
||||||
|
add_timer(Server, {iq, ID}, JID, {From, To, El}),
|
||||||
|
ejabberd_router:route(jlib:make_jid("", Server, ""), JID,
|
||||||
|
{xmlelement, "iq",
|
||||||
|
[{"type", "get"}, {"id", ID}],
|
||||||
|
[{xmlelement, "query", [{"xmlns", ?NS_PING}], []}]}).
|
||||||
|
|
||||||
|
add_timer(Host, ID, JID, Packet) ->
|
||||||
|
{U, S, R} = jlib:jid_tolower(JID),
|
||||||
|
C2SPid = ejabberd_sm:get_session_pid(U, S, R),
|
||||||
|
gen_server:cast(gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||||
|
{add, ID, C2SPid, Packet}).
|
||||||
|
|
||||||
|
del_timer(Host, ID, JID) ->
|
||||||
|
{U, S, R} = jlib:jid_tolower(JID),
|
||||||
|
C2SPid = ejabberd_sm:get_session_pid(U, S, R),
|
||||||
|
gen_server:cast(gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||||
|
{del, ID, C2SPid}).
|
||||||
|
|
||||||
|
cancel_timer(TRef) ->
|
||||||
|
case erlang:cancel_timer(TRef) of
|
||||||
|
false ->
|
||||||
|
receive
|
||||||
|
{timeout, TRef, _} ->
|
||||||
|
ok
|
||||||
|
after 0 ->
|
||||||
|
ok
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end.
|
||||||
|
|
||||||
|
lookup(Pid, Key, Queue) ->
|
||||||
|
case ?DICT:find(Pid, Queue) of
|
||||||
|
{ok, Treap} ->
|
||||||
|
case treap:lookup(Key, Treap) of
|
||||||
|
{ok, _, Val} ->
|
||||||
|
{ok, Val};
|
||||||
|
error ->
|
||||||
|
error
|
||||||
|
end;
|
||||||
|
error ->
|
||||||
|
error
|
||||||
|
end.
|
||||||
|
|
||||||
|
insert(Pid, Key, Val, Queue) ->
|
||||||
|
Treap = case ?DICT:find(Pid, Queue) of
|
||||||
|
{ok, Treap1} ->
|
||||||
|
Treap1;
|
||||||
|
error ->
|
||||||
|
nil
|
||||||
|
end,
|
||||||
|
?DICT:store(Pid, treap:insert(Key, now(), Val, Treap), Queue).
|
||||||
|
|
||||||
|
delete(Pid, Key, Queue) ->
|
||||||
|
case ?DICT:find(Pid, Queue) of
|
||||||
|
{ok, Treap} ->
|
||||||
|
NewTreap = treap:delete(Key, Treap),
|
||||||
|
case treap:is_empty(NewTreap) of
|
||||||
|
true ->
|
||||||
|
?DICT:erase(Pid, Queue);
|
||||||
|
false ->
|
||||||
|
?DICT:store(Pid, NewTreap, Queue)
|
||||||
|
end;
|
||||||
|
error ->
|
||||||
|
Queue
|
||||||
|
end.
|
||||||
|
|
||||||
|
delete(Pid, Queue) ->
|
||||||
|
?DICT:erase(Pid, Queue).
|
||||||
|
|
||||||
|
to_list(Pid, Queue) ->
|
||||||
|
case ?DICT:find(Pid, Queue) of
|
||||||
|
{ok, Treap} ->
|
||||||
|
treap:to_list(Treap);
|
||||||
|
error ->
|
||||||
|
[]
|
||||||
|
end.
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 15 Nov 2005 by Magnus Henoch <henoch@dtek.chalmers.se>
|
%%% Created : 15 Nov 2005 by Magnus Henoch <henoch@dtek.chalmers.se>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 11 Aug 2003 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 11 Aug 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
333
src/mod_blocking.erl
Normal file
333
src/mod_blocking.erl
Normal file
@ -0,0 +1,333 @@
|
|||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
%%% File : mod_blocking.erl
|
||||||
|
%%% Author : Stephan Maka
|
||||||
|
%%% Purpose : XEP-0191: Simple Communications Blocking
|
||||||
|
%%% Created : 24 Aug 2008 by Stephan Maka <stephan@spaceboyz.net>
|
||||||
|
%%%
|
||||||
|
%%%
|
||||||
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
|
%%%
|
||||||
|
%%% This program is free software; you can redistribute it and/or
|
||||||
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
%%% published by the Free Software Foundation; either version 2 of the
|
||||||
|
%%% License, or (at your option) any later version.
|
||||||
|
%%%
|
||||||
|
%%% This program is distributed in the hope that it will be useful,
|
||||||
|
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
%%% General Public License for more details.
|
||||||
|
%%%
|
||||||
|
%%% You should have received a copy of the GNU General Public License
|
||||||
|
%%% along with this program; if not, write to the Free Software
|
||||||
|
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
|
%%% 02111-1307 USA
|
||||||
|
%%%
|
||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
|
-module(mod_blocking).
|
||||||
|
|
||||||
|
-behaviour(gen_mod).
|
||||||
|
|
||||||
|
-export([start/2, stop/1,
|
||||||
|
process_iq/3,
|
||||||
|
process_iq_set/4,
|
||||||
|
process_iq_get/5]).
|
||||||
|
|
||||||
|
-include("ejabberd.hrl").
|
||||||
|
-include("jlib.hrl").
|
||||||
|
-include("mod_privacy.hrl").
|
||||||
|
|
||||||
|
start(Host, Opts) ->
|
||||||
|
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
|
||||||
|
ejabberd_hooks:add(privacy_iq_get, Host,
|
||||||
|
?MODULE, process_iq_get, 40),
|
||||||
|
ejabberd_hooks:add(privacy_iq_set, Host,
|
||||||
|
?MODULE, process_iq_set, 40),
|
||||||
|
mod_disco:register_feature(Host, ?NS_BLOCKING),
|
||||||
|
gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_BLOCKING,
|
||||||
|
?MODULE, process_iq, IQDisc).
|
||||||
|
|
||||||
|
stop(Host) ->
|
||||||
|
ejabberd_hooks:delete(privacy_iq_get, Host,
|
||||||
|
?MODULE, process_iq_get, 40),
|
||||||
|
ejabberd_hooks:delete(privacy_iq_set, Host,
|
||||||
|
?MODULE, process_iq_set, 40),
|
||||||
|
mod_disco:unregister_feature(Host, ?NS_BLOCKING),
|
||||||
|
gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_BLOCKING).
|
||||||
|
|
||||||
|
process_iq(_From, _To, IQ) ->
|
||||||
|
SubEl = IQ#iq.sub_el,
|
||||||
|
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}.
|
||||||
|
|
||||||
|
process_iq_get(_, From, _To,
|
||||||
|
#iq{xmlns = ?NS_BLOCKING,
|
||||||
|
sub_el = {xmlelement, "blocklist", _, _}},
|
||||||
|
_) ->
|
||||||
|
#jid{luser = LUser, lserver = LServer} = From,
|
||||||
|
process_blocklist_get(LUser, LServer);
|
||||||
|
|
||||||
|
process_iq_get(Acc, _, _, _, _) ->
|
||||||
|
Acc.
|
||||||
|
|
||||||
|
process_iq_set(_, From, _To, #iq{xmlns = ?NS_BLOCKING,
|
||||||
|
sub_el = {xmlelement, SubElName, _, SubEls}}) ->
|
||||||
|
#jid{luser = LUser, lserver = LServer} = From,
|
||||||
|
case {SubElName, xml:remove_cdata(SubEls)} of
|
||||||
|
{"block", []} ->
|
||||||
|
{error, ?ERR_BAD_REQUEST};
|
||||||
|
{"block", Els} ->
|
||||||
|
JIDs = parse_blocklist_items(Els, []),
|
||||||
|
process_blocklist_block(LUser, LServer, JIDs);
|
||||||
|
{"unblock", []} ->
|
||||||
|
process_blocklist_unblock_all(LUser, LServer);
|
||||||
|
{"unblock", Els} ->
|
||||||
|
JIDs = parse_blocklist_items(Els, []),
|
||||||
|
process_blocklist_unblock(LUser, LServer, JIDs);
|
||||||
|
_ ->
|
||||||
|
{error, ?ERR_BAD_REQUEST}
|
||||||
|
end;
|
||||||
|
|
||||||
|
process_iq_set(Acc, _, _, _) ->
|
||||||
|
Acc.
|
||||||
|
|
||||||
|
is_list_needdb(Items) ->
|
||||||
|
lists:any(
|
||||||
|
fun(X) ->
|
||||||
|
case X#listitem.type of
|
||||||
|
subscription -> true;
|
||||||
|
group -> true;
|
||||||
|
_ -> false
|
||||||
|
end
|
||||||
|
end, Items).
|
||||||
|
|
||||||
|
list_to_blocklist_jids([], JIDs) ->
|
||||||
|
JIDs;
|
||||||
|
|
||||||
|
list_to_blocklist_jids([#listitem{type = jid,
|
||||||
|
action = deny,
|
||||||
|
value = JID} = Item | Items], JIDs) ->
|
||||||
|
case Item of
|
||||||
|
#listitem{match_all = true} ->
|
||||||
|
Match = true;
|
||||||
|
#listitem{match_iq = true,
|
||||||
|
match_message = true,
|
||||||
|
match_presence_in = true,
|
||||||
|
match_presence_out = true} ->
|
||||||
|
Match = true;
|
||||||
|
_ ->
|
||||||
|
Match = false
|
||||||
|
end,
|
||||||
|
if
|
||||||
|
Match ->
|
||||||
|
list_to_blocklist_jids(Items, [JID | JIDs]);
|
||||||
|
true ->
|
||||||
|
list_to_blocklist_jids(Items, JIDs)
|
||||||
|
end;
|
||||||
|
|
||||||
|
% Skip Privacy List items than cannot be mapped to Blocking items
|
||||||
|
list_to_blocklist_jids([_ | Items], JIDs) ->
|
||||||
|
list_to_blocklist_jids(Items, JIDs).
|
||||||
|
|
||||||
|
parse_blocklist_items([], JIDs) ->
|
||||||
|
JIDs;
|
||||||
|
|
||||||
|
parse_blocklist_items([{xmlelement, "item", Attrs, _} | Els], JIDs) ->
|
||||||
|
case xml:get_attr("jid", Attrs) of
|
||||||
|
{value, JID1} ->
|
||||||
|
JID = jlib:jid_tolower(jlib:string_to_jid(JID1)),
|
||||||
|
parse_blocklist_items(Els, [JID | JIDs]);
|
||||||
|
false ->
|
||||||
|
% Tolerate missing jid attribute
|
||||||
|
parse_blocklist_items(Els, JIDs)
|
||||||
|
end;
|
||||||
|
|
||||||
|
parse_blocklist_items([_ | Els], JIDs) ->
|
||||||
|
% Tolerate unknown elements
|
||||||
|
parse_blocklist_items(Els, JIDs).
|
||||||
|
|
||||||
|
process_blocklist_block(LUser, LServer, JIDs) ->
|
||||||
|
F =
|
||||||
|
fun() ->
|
||||||
|
case mnesia:wread({privacy, {LUser, LServer}}) of
|
||||||
|
[] ->
|
||||||
|
% No lists yet
|
||||||
|
P = #privacy{us = {LUser, LServer}},
|
||||||
|
% TODO: i18n here:
|
||||||
|
NewDefault = "Blocked contacts",
|
||||||
|
NewLists1 = [],
|
||||||
|
List = [];
|
||||||
|
[#privacy{default = Default,
|
||||||
|
lists = Lists} = P] ->
|
||||||
|
case lists:keysearch(Default, 1, Lists) of
|
||||||
|
{value, {_, List}} ->
|
||||||
|
% Default list exists
|
||||||
|
NewDefault = Default,
|
||||||
|
NewLists1 = lists:keydelete(Default, 1, Lists);
|
||||||
|
false ->
|
||||||
|
% No default list yet, create one
|
||||||
|
% TODO: i18n here:
|
||||||
|
NewDefault = "Blocked contacts",
|
||||||
|
NewLists1 = Lists,
|
||||||
|
List = []
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
AlreadyBlocked = list_to_blocklist_jids(List, []),
|
||||||
|
NewList =
|
||||||
|
lists:foldr(fun(JID, List1) ->
|
||||||
|
case lists:member(JID, AlreadyBlocked) of
|
||||||
|
true ->
|
||||||
|
List1;
|
||||||
|
false ->
|
||||||
|
[#listitem{type = jid,
|
||||||
|
value = JID,
|
||||||
|
action = deny,
|
||||||
|
order = 0,
|
||||||
|
match_all = true
|
||||||
|
} | List1]
|
||||||
|
end
|
||||||
|
end, List, JIDs),
|
||||||
|
NewLists = [{NewDefault, NewList} | NewLists1],
|
||||||
|
mnesia:write(P#privacy{default = NewDefault,
|
||||||
|
lists = NewLists}),
|
||||||
|
{ok, NewDefault, NewList}
|
||||||
|
end,
|
||||||
|
case mnesia:transaction(F) of
|
||||||
|
{atomic, {error, _} = Error} ->
|
||||||
|
Error;
|
||||||
|
{atomic, {ok, Default, List}} ->
|
||||||
|
broadcast_list_update(LUser, LServer, Default, List),
|
||||||
|
broadcast_blocklist_event(LUser, LServer, {block, JIDs}),
|
||||||
|
{result, []};
|
||||||
|
_ ->
|
||||||
|
{error, ?ERR_INTERNAL_SERVER_ERROR}
|
||||||
|
end.
|
||||||
|
|
||||||
|
process_blocklist_unblock_all(LUser, LServer) ->
|
||||||
|
F =
|
||||||
|
fun() ->
|
||||||
|
case mnesia:read({privacy, {LUser, LServer}}) of
|
||||||
|
[] ->
|
||||||
|
% No lists, nothing to unblock
|
||||||
|
ok;
|
||||||
|
[#privacy{default = Default,
|
||||||
|
lists = Lists} = P] ->
|
||||||
|
case lists:keysearch(Default, 1, Lists) of
|
||||||
|
{value, {_, List}} ->
|
||||||
|
% Default list, remove all deny items
|
||||||
|
NewList =
|
||||||
|
lists:filter(
|
||||||
|
fun(#listitem{action = A}) ->
|
||||||
|
A =/= deny
|
||||||
|
end, List),
|
||||||
|
|
||||||
|
NewLists1 = lists:keydelete(Default, 1, Lists),
|
||||||
|
NewLists = [{Default, NewList} | NewLists1],
|
||||||
|
mnesia:write(P#privacy{lists = NewLists}),
|
||||||
|
|
||||||
|
{ok, Default, NewList};
|
||||||
|
false ->
|
||||||
|
% No default list, nothing to unblock
|
||||||
|
ok
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
case mnesia:transaction(F) of
|
||||||
|
{atomic, {error, _} = Error} ->
|
||||||
|
Error;
|
||||||
|
{atomic, ok} ->
|
||||||
|
{result, []};
|
||||||
|
{atomic, {ok, Default, List}} ->
|
||||||
|
broadcast_list_update(LUser, LServer, Default, List),
|
||||||
|
broadcast_blocklist_event(LUser, LServer, unblock_all),
|
||||||
|
{result, []};
|
||||||
|
_ ->
|
||||||
|
{error, ?ERR_INTERNAL_SERVER_ERROR}
|
||||||
|
end.
|
||||||
|
|
||||||
|
process_blocklist_unblock(LUser, LServer, JIDs) ->
|
||||||
|
F =
|
||||||
|
fun() ->
|
||||||
|
case mnesia:read({privacy, {LUser, LServer}}) of
|
||||||
|
[] ->
|
||||||
|
% No lists, nothing to unblock
|
||||||
|
ok;
|
||||||
|
[#privacy{default = Default,
|
||||||
|
lists = Lists} = P] ->
|
||||||
|
case lists:keysearch(Default, 1, Lists) of
|
||||||
|
{value, {_, List}} ->
|
||||||
|
% Default list, remove matching deny items
|
||||||
|
NewList =
|
||||||
|
lists:filter(
|
||||||
|
fun(#listitem{action = deny,
|
||||||
|
type = jid,
|
||||||
|
value = JID}) ->
|
||||||
|
not(lists:member(JID, JIDs));
|
||||||
|
(_) ->
|
||||||
|
true
|
||||||
|
end, List),
|
||||||
|
|
||||||
|
NewLists1 = lists:keydelete(Default, 1, Lists),
|
||||||
|
NewLists = [{Default, NewList} | NewLists1],
|
||||||
|
mnesia:write(P#privacy{lists = NewLists}),
|
||||||
|
|
||||||
|
{ok, Default, NewList};
|
||||||
|
false ->
|
||||||
|
% No default list, nothing to unblock
|
||||||
|
ok
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
case mnesia:transaction(F) of
|
||||||
|
{atomic, {error, _} = Error} ->
|
||||||
|
Error;
|
||||||
|
{atomic, ok} ->
|
||||||
|
{result, []};
|
||||||
|
{atomic, {ok, Default, List}} ->
|
||||||
|
broadcast_list_update(LUser, LServer, Default, List),
|
||||||
|
broadcast_blocklist_event(LUser, LServer, {unblock, JIDs}),
|
||||||
|
{result, []};
|
||||||
|
_ ->
|
||||||
|
{error, ?ERR_INTERNAL_SERVER_ERROR}
|
||||||
|
end.
|
||||||
|
|
||||||
|
broadcast_list_update(LUser, LServer, Name, List) ->
|
||||||
|
NeedDb = is_list_needdb(List),
|
||||||
|
ejabberd_router:route(
|
||||||
|
jlib:make_jid(LUser, LServer, ""),
|
||||||
|
jlib:make_jid(LUser, LServer, ""),
|
||||||
|
{xmlelement, "broadcast", [],
|
||||||
|
[{privacy_list,
|
||||||
|
#userlist{name = Name, list = List, needdb = NeedDb},
|
||||||
|
Name}]}).
|
||||||
|
|
||||||
|
broadcast_blocklist_event(LUser, LServer, Event) ->
|
||||||
|
JID = jlib:make_jid(LUser, LServer, ""),
|
||||||
|
ejabberd_router:route(
|
||||||
|
JID, JID,
|
||||||
|
{xmlelement, "broadcast", [],
|
||||||
|
[{blocking, Event}]}).
|
||||||
|
|
||||||
|
process_blocklist_get(LUser, LServer) ->
|
||||||
|
case catch mnesia:dirty_read(privacy, {LUser, LServer}) of
|
||||||
|
{'EXIT', _Reason} ->
|
||||||
|
{error, ?ERR_INTERNAL_SERVER_ERROR};
|
||||||
|
[] ->
|
||||||
|
{result, [{xmlelement, "blocklist", [{"xmlns", ?NS_BLOCKING}], []}]};
|
||||||
|
[#privacy{default = Default, lists = Lists}] ->
|
||||||
|
case lists:keysearch(Default, 1, Lists) of
|
||||||
|
{value, {_, List}} ->
|
||||||
|
JIDs = list_to_blocklist_jids(List, []),
|
||||||
|
Items = lists:map(
|
||||||
|
fun(JID) ->
|
||||||
|
?DEBUG("JID: ~p",[JID]),
|
||||||
|
{xmlelement, "item",
|
||||||
|
[{"jid", jlib:jid_to_string(JID)}], []}
|
||||||
|
end, JIDs),
|
||||||
|
{result,
|
||||||
|
[{xmlelement, "blocklist", [{"xmlns", ?NS_BLOCKING}],
|
||||||
|
Items}]};
|
||||||
|
_ ->
|
||||||
|
{result, [{xmlelement, "blocklist", [{"xmlns", ?NS_BLOCKING}], []}]}
|
||||||
|
end
|
||||||
|
end.
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 7 Oct 2006 by Magnus Henoch <henoch@dtek.chalmers.se>
|
%%% Created : 7 Oct 2006 by Magnus Henoch <henoch@dtek.chalmers.se>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 19 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 19 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 26 Oct 2003 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 26 Oct 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 1 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 1 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 15 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 15 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
%%% {mod_ip_blacklist, []}
|
%%% {mod_ip_blacklist, []}
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 16 Feb 2003 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 16 Feb 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% 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-2011 ProcessOne
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License as
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 15 Feb 2003 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 15 Feb 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
@ -425,7 +425,7 @@ iq_get_vcard(Lang) ->
|
|||||||
[{xmlcdata, ?EJABBERD_URI}]},
|
[{xmlcdata, ?EJABBERD_URI}]},
|
||||||
{xmlelement, "DESC", [],
|
{xmlelement, "DESC", [],
|
||||||
[{xmlcdata, translate:translate(Lang, "ejabberd IRC module") ++
|
[{xmlcdata, translate:translate(Lang, "ejabberd IRC module") ++
|
||||||
"\nCopyright (c) 2003-2010 Alexey Shchepin"}]}].
|
"\nCopyright (c) 2003-2011 ProcessOne"}]}].
|
||||||
|
|
||||||
command_items(Host, Lang) ->
|
command_items(Host, Lang) ->
|
||||||
lists:map(fun({Node, Name, _Function})
|
lists:map(fun({Node, Name, _Function})
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 15 Feb 2003 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 15 Feb 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
@ -219,6 +219,7 @@ handle_info({route_chan, Channel, Resource,
|
|||||||
NewStateData =
|
NewStateData =
|
||||||
case xml:get_attr_s("type", Attrs) of
|
case xml:get_attr_s("type", Attrs) of
|
||||||
"unavailable" ->
|
"unavailable" ->
|
||||||
|
send_stanza_unavailable(Channel, StateData),
|
||||||
S1 = ?SEND(io_lib:format("PART #~s\r\n", [Channel])),
|
S1 = ?SEND(io_lib:format("PART #~s\r\n", [Channel])),
|
||||||
S1#state{channels =
|
S1#state{channels =
|
||||||
dict:erase(Channel, S1#state.channels)};
|
dict:erase(Channel, S1#state.channels)};
|
||||||
@ -656,13 +657,9 @@ terminate(_Reason, _StateName, FullStateData) ->
|
|||||||
bounce_messages("Server Connect Failed"),
|
bounce_messages("Server Connect Failed"),
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun(Chan) ->
|
fun(Chan) ->
|
||||||
ejabberd_router:route(
|
Stanza = {xmlelement, "presence", [{"type", "error"}],
|
||||||
jlib:make_jid(
|
[Error]},
|
||||||
lists:concat([Chan, "%", StateData#state.server]),
|
send_stanza(Chan, StateData, Stanza)
|
||||||
StateData#state.host, StateData#state.nick),
|
|
||||||
StateData#state.user,
|
|
||||||
{xmlelement, "presence", [{"type", "error"}],
|
|
||||||
[Error]})
|
|
||||||
end, dict:fetch_keys(StateData#state.channels)),
|
end, dict:fetch_keys(StateData#state.channels)),
|
||||||
case StateData#state.socket of
|
case StateData#state.socket of
|
||||||
undefined ->
|
undefined ->
|
||||||
@ -672,6 +669,30 @@ terminate(_Reason, _StateName, FullStateData) ->
|
|||||||
end,
|
end,
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
send_stanza(Chan, StateData, Stanza) ->
|
||||||
|
ejabberd_router:route(
|
||||||
|
jlib:make_jid(
|
||||||
|
lists:concat([Chan, "%", StateData#state.server]),
|
||||||
|
StateData#state.host, StateData#state.nick),
|
||||||
|
StateData#state.user,
|
||||||
|
Stanza).
|
||||||
|
|
||||||
|
send_stanza_unavailable(Chan, StateData) ->
|
||||||
|
Affiliation = "member", % this is a simplification
|
||||||
|
Role = "none",
|
||||||
|
Stanza =
|
||||||
|
{xmlelement, "presence", [{"type", "unavailable"}],
|
||||||
|
[{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}],
|
||||||
|
[{xmlelement, "item",
|
||||||
|
[{"affiliation", Affiliation},
|
||||||
|
{"role", Role}],
|
||||||
|
[]},
|
||||||
|
{xmlelement, "status",
|
||||||
|
[{"code", "110"}],
|
||||||
|
[]}
|
||||||
|
]}]},
|
||||||
|
send_stanza(Chan, StateData, Stanza).
|
||||||
|
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
%%% Internal functions
|
%%% Internal functions
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 24 Oct 2003 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 24 Oct 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
@ -116,7 +116,9 @@ process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) ->
|
|||||||
roster_get_jid_info, Server,
|
roster_get_jid_info, Server,
|
||||||
{none, []}, [User, Server, From]),
|
{none, []}, [User, Server, From]),
|
||||||
if
|
if
|
||||||
(Subscription == both) or (Subscription == from) ->
|
(Subscription == both) or (Subscription == from)
|
||||||
|
or ((From#jid.luser == To#jid.luser)
|
||||||
|
and (From#jid.lserver == To#jid.lserver)) ->
|
||||||
UserListRecord = ejabberd_hooks:run_fold(
|
UserListRecord = ejabberd_hooks:run_fold(
|
||||||
privacy_get_user_list, Server,
|
privacy_get_user_list, Server,
|
||||||
#userlist{},
|
#userlist{},
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 24 Oct 2003 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 24 Oct 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 19 Mar 2003 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 19 Mar 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
@ -42,6 +42,7 @@
|
|||||||
process_iq_disco_items/4,
|
process_iq_disco_items/4,
|
||||||
broadcast_service_message/2,
|
broadcast_service_message/2,
|
||||||
register_room/3,
|
register_room/3,
|
||||||
|
node_up/1,
|
||||||
migrate/1,
|
migrate/1,
|
||||||
get_vh_rooms/1,
|
get_vh_rooms/1,
|
||||||
can_use_nick/3]).
|
can_use_nick/3]).
|
||||||
@ -175,14 +176,33 @@ migrate(After) ->
|
|||||||
['$$']}]),
|
['$$']}]),
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun([NameHost, Pid]) ->
|
fun([NameHost, Pid]) ->
|
||||||
case ejabberd_cluster:get_node_new(NameHost) of
|
case ejabberd_cluster:get_node(NameHost) of
|
||||||
Node when Node /= node() ->
|
Node when Node /= node() ->
|
||||||
mod_muc_room:migrate(Pid, Node, After);
|
mod_muc_room:migrate(Pid, Node, random:uniform(After));
|
||||||
_ ->
|
_ ->
|
||||||
ok
|
ok
|
||||||
end
|
end
|
||||||
end, Rs).
|
end, Rs).
|
||||||
|
|
||||||
|
node_up(_Node) ->
|
||||||
|
copy_rooms(mnesia:dirty_first(muc_online_room)).
|
||||||
|
|
||||||
|
copy_rooms('$end_of_table') ->
|
||||||
|
ok;
|
||||||
|
copy_rooms(Key) ->
|
||||||
|
case mnesia:dirty_read(muc_online_room, Key) of
|
||||||
|
[#muc_online_room{name_host = NameHost} = Room] ->
|
||||||
|
case ejabberd_cluster:get_node_new(NameHost) of
|
||||||
|
Node when node() /= Node ->
|
||||||
|
rpc:cast(Node, mnesia, dirty_write, [Room]);
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
|
copy_rooms(mnesia:dirty_next(muc_online_room, Key)).
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
@ -219,6 +239,7 @@ init([Host, Opts]) ->
|
|||||||
DefRoomOpts = gen_mod:get_opt(default_room_options, Opts, []),
|
DefRoomOpts = gen_mod:get_opt(default_room_options, Opts, []),
|
||||||
RoomShaper = gen_mod:get_opt(room_shaper, Opts, none),
|
RoomShaper = gen_mod:get_opt(room_shaper, Opts, none),
|
||||||
ejabberd_router:register_route(MyHost),
|
ejabberd_router:register_route(MyHost),
|
||||||
|
ejabberd_hooks:add(node_up, ?MODULE, node_up, 100),
|
||||||
ejabberd_hooks:add(node_hash_update, ?MODULE, migrate, 100),
|
ejabberd_hooks:add(node_hash_update, ?MODULE, migrate, 100),
|
||||||
load_permanent_rooms(MyHost, Host,
|
load_permanent_rooms(MyHost, Host,
|
||||||
{Access, AccessCreate, AccessAdmin, AccessPersistent},
|
{Access, AccessCreate, AccessAdmin, AccessPersistent},
|
||||||
@ -306,7 +327,15 @@ handle_info({room_destroyed, RoomHost, Pid}, State) ->
|
|||||||
mnesia:delete_object(#muc_online_room{name_host = RoomHost,
|
mnesia:delete_object(#muc_online_room{name_host = RoomHost,
|
||||||
pid = Pid})
|
pid = Pid})
|
||||||
end,
|
end,
|
||||||
mnesia:sync_dirty(F),
|
mnesia:async_dirty(F),
|
||||||
|
case ejabberd_cluster:get_node_new(RoomHost) of
|
||||||
|
Node when Node /= node() ->
|
||||||
|
rpc:cast(Node, mnesia, dirty_delete_object,
|
||||||
|
[#muc_online_room{name_host = RoomHost,
|
||||||
|
pid = Pid}]);
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
{noreply, State};
|
{noreply, State};
|
||||||
handle_info(_Info, State) ->
|
handle_info(_Info, State) ->
|
||||||
{noreply, State}.
|
{noreply, State}.
|
||||||
@ -319,6 +348,7 @@ handle_info(_Info, State) ->
|
|||||||
%% The return value is ignored.
|
%% The return value is ignored.
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
terminate(_Reason, State) ->
|
terminate(_Reason, State) ->
|
||||||
|
ejabberd_hooks:delete(node_up, ?MODULE, node_up, 100),
|
||||||
ejabberd_hooks:delete(node_hash_update, ?MODULE, migrate, 100),
|
ejabberd_hooks:delete(node_hash_update, ?MODULE, migrate, 100),
|
||||||
ejabberd_router:unregister_route(State#state.host),
|
ejabberd_router:unregister_route(State#state.host),
|
||||||
ok.
|
ok.
|
||||||
@ -507,14 +537,20 @@ do_route1(Host, ServerHost, Access, HistorySize, RoomShaper,
|
|||||||
AccessCreate, From,
|
AccessCreate, From,
|
||||||
Room) of
|
Room) of
|
||||||
true ->
|
true ->
|
||||||
{ok, Pid} = start_new_room(
|
case start_new_room(
|
||||||
Host, ServerHost, Access,
|
Host, ServerHost, Access,
|
||||||
Room, HistorySize,
|
Room, HistorySize,
|
||||||
RoomShaper, From,
|
RoomShaper, From,
|
||||||
Nick, DefRoomOpts),
|
Nick, DefRoomOpts) of
|
||||||
register_room(Host, Room, Pid),
|
{ok, Pid} ->
|
||||||
mod_muc_room:route(Pid, From, Nick, Packet),
|
mod_muc_room:route(Pid, From, Nick, Packet),
|
||||||
|
register_room(Host, Room, Pid),
|
||||||
ok;
|
ok;
|
||||||
|
_Err ->
|
||||||
|
Err = jlib:make_error_reply(
|
||||||
|
Packet, ?ERR_INTERNAL_SERVER_ERROR),
|
||||||
|
ejabberd_router:route(To, From, Err)
|
||||||
|
end;
|
||||||
false ->
|
false ->
|
||||||
Lang = xml:get_attr_s("xml:lang", Attrs),
|
Lang = xml:get_attr_s("xml:lang", Attrs),
|
||||||
ErrText = "Room creation is denied by service policy",
|
ErrText = "Room creation is denied by service policy",
|
||||||
@ -603,7 +639,28 @@ register_room(Host, Room, Pid) ->
|
|||||||
mnesia:write(#muc_online_room{name_host = {Room, Host},
|
mnesia:write(#muc_online_room{name_host = {Room, Host},
|
||||||
pid = Pid})
|
pid = Pid})
|
||||||
end,
|
end,
|
||||||
mnesia:sync_dirty(F).
|
mnesia:async_dirty(F),
|
||||||
|
case ejabberd_cluster:get_node_new({Room, Host}) of
|
||||||
|
Node when Node /= node() ->
|
||||||
|
%% New node has just been added. But we may miss MUC records
|
||||||
|
%% copy procedure, so we copy the MUC record manually just
|
||||||
|
%% to make sure
|
||||||
|
rpc:cast(Node, mnesia, dirty_write,
|
||||||
|
[#muc_online_room{name_host = {Room, Host},
|
||||||
|
pid = Pid}]),
|
||||||
|
case ejabberd_cluster:get_node({Room, Host}) of
|
||||||
|
Node when node() /= Node ->
|
||||||
|
%% Migration to new node has completed, and seems like
|
||||||
|
%% we missed it, so we migrate the MUC room pid manually.
|
||||||
|
%% It is not a problem if we have already got migration
|
||||||
|
%% notification: dups are just ignored by the MUC room pid.
|
||||||
|
mod_muc_room:migrate(Pid, Node, 0);
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end.
|
||||||
|
|
||||||
iq_disco_info(Lang) ->
|
iq_disco_info(Lang) ->
|
||||||
[{xmlelement, "identity",
|
[{xmlelement, "identity",
|
||||||
@ -847,7 +904,7 @@ iq_get_vcard(Lang) ->
|
|||||||
[{xmlcdata, ?EJABBERD_URI}]},
|
[{xmlcdata, ?EJABBERD_URI}]},
|
||||||
{xmlelement, "DESC", [],
|
{xmlelement, "DESC", [],
|
||||||
[{xmlcdata, translate:translate(Lang, "ejabberd MUC module") ++
|
[{xmlcdata, translate:translate(Lang, "ejabberd MUC module") ++
|
||||||
"\nCopyright (c) 2003-2010 Alexey Shchepin"}]}].
|
"\nCopyright (c) 2003-2011 ProcessOne"}]}].
|
||||||
|
|
||||||
|
|
||||||
broadcast_service_message(Host, Msg) ->
|
broadcast_service_message(Host, Msg) ->
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 12 Mar 2006 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 12 Mar 2006 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 19 Mar 2003 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 19 Mar 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
@ -110,7 +110,7 @@ start_link(StateName, StateData) ->
|
|||||||
?GEN_FSM:start_link(?MODULE, [StateName, StateData], ?FSMOPTS).
|
?GEN_FSM:start_link(?MODULE, [StateName, StateData], ?FSMOPTS).
|
||||||
|
|
||||||
migrate(FsmRef, Node, After) ->
|
migrate(FsmRef, Node, After) ->
|
||||||
?GEN_FSM:send_all_state_event(FsmRef, {migrate, Node, After}).
|
erlang:send_after(After, FsmRef, {migrate, Node}).
|
||||||
|
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
%%% Callback functions from gen_fsm
|
%%% Callback functions from gen_fsm
|
||||||
@ -597,9 +597,6 @@ handle_event(destroy, StateName, StateData) ->
|
|||||||
handle_event({set_affiliations, Affiliations}, StateName, StateData) ->
|
handle_event({set_affiliations, Affiliations}, StateName, StateData) ->
|
||||||
{next_state, StateName, StateData#state{affiliations = Affiliations}};
|
{next_state, StateName, StateData#state{affiliations = Affiliations}};
|
||||||
|
|
||||||
handle_event({migrate, Node, After}, StateName, StateData) when Node /= node() ->
|
|
||||||
{migrate, StateData,
|
|
||||||
{Node, ?MODULE, start, [StateName, StateData]}, After * 2};
|
|
||||||
handle_event(_Event, StateName, StateData) ->
|
handle_event(_Event, StateName, StateData) ->
|
||||||
{next_state, StateName, StateData}.
|
{next_state, StateName, StateData}.
|
||||||
|
|
||||||
@ -716,6 +713,13 @@ handle_info({captcha_failed, From}, normal_state, StateData) ->
|
|||||||
StateData
|
StateData
|
||||||
end,
|
end,
|
||||||
{next_state, normal_state, NewState};
|
{next_state, normal_state, NewState};
|
||||||
|
handle_info({migrate, Node}, StateName, StateData) ->
|
||||||
|
if Node /= node() ->
|
||||||
|
{migrate, StateData,
|
||||||
|
{Node, ?MODULE, start, [StateName, StateData]}, 0};
|
||||||
|
true ->
|
||||||
|
{next_state, StateName, StateData}
|
||||||
|
end;
|
||||||
handle_info(_Info, StateName, StateData) ->
|
handle_info(_Info, StateName, StateData) ->
|
||||||
{next_state, StateName, StateData}.
|
{next_state, StateName, StateData}.
|
||||||
|
|
||||||
@ -870,9 +874,6 @@ process_groupchat_message(From, {xmlelement, "message", Attrs, _Els} = Packet,
|
|||||||
%% an implementation MAY allow users with certain privileges
|
%% an implementation MAY allow users with certain privileges
|
||||||
%% (e.g., a room owner, room admin, or service-level admin)
|
%% (e.g., a room owner, room admin, or service-level admin)
|
||||||
%% to send messages to the room even if those users are not occupants.
|
%% to send messages to the room even if those users are not occupants.
|
||||||
%%
|
|
||||||
%% Check the mod_muc option access_message_nonparticipant and wether this JID
|
|
||||||
%% is allowed or denied
|
|
||||||
is_user_allowed_message_nonparticipant(JID, StateData) ->
|
is_user_allowed_message_nonparticipant(JID, StateData) ->
|
||||||
case get_service_affiliation(JID, StateData) of
|
case get_service_affiliation(JID, StateData) of
|
||||||
owner ->
|
owner ->
|
||||||
@ -1665,15 +1666,25 @@ add_new_user(From, Nick, {xmlelement, _, Attrs, Els} = Packet, StateData) ->
|
|||||||
SID = xml:get_attr_s("id", Attrs),
|
SID = xml:get_attr_s("id", Attrs),
|
||||||
RoomJID = StateData#state.jid,
|
RoomJID = StateData#state.jid,
|
||||||
To = jlib:jid_replace_resource(RoomJID, Nick),
|
To = jlib:jid_replace_resource(RoomJID, Nick),
|
||||||
|
Limiter = {From#jid.luser, From#jid.lserver},
|
||||||
case ejabberd_captcha:create_captcha(
|
case ejabberd_captcha:create_captcha(
|
||||||
SID, RoomJID, To, Lang, From) of
|
SID, RoomJID, To, Lang, Limiter, From) of
|
||||||
{ok, ID, CaptchaEls} ->
|
{ok, ID, CaptchaEls} ->
|
||||||
MsgPkt = {xmlelement, "message", [{"id", ID}], CaptchaEls},
|
MsgPkt = {xmlelement, "message", [{"id", ID}], CaptchaEls},
|
||||||
Robots = ?DICT:store(From,
|
Robots = ?DICT:store(From,
|
||||||
{Nick, Packet}, StateData#state.robots),
|
{Nick, Packet}, StateData#state.robots),
|
||||||
ejabberd_router:route(RoomJID, From, MsgPkt),
|
ejabberd_router:route(RoomJID, From, MsgPkt),
|
||||||
StateData#state{robots = Robots};
|
StateData#state{robots = Robots};
|
||||||
error ->
|
{error, limit} ->
|
||||||
|
ErrText = "Too many CAPTCHA requests",
|
||||||
|
Err = jlib:make_error_reply(
|
||||||
|
Packet, ?ERRT_RESOURCE_CONSTRAINT(Lang, ErrText)),
|
||||||
|
ejabberd_router:route( % TODO: s/Nick/""/
|
||||||
|
jlib:jid_replace_resource(
|
||||||
|
StateData#state.jid, Nick),
|
||||||
|
From, Err),
|
||||||
|
StateData;
|
||||||
|
_ ->
|
||||||
ErrText = "Unable to generate a captcha",
|
ErrText = "Unable to generate a captcha",
|
||||||
Err = jlib:make_error_reply(
|
Err = jlib:make_error_reply(
|
||||||
Packet, ?ERRT_INTERNAL_SERVER_ERROR(Lang, ErrText)),
|
Packet, ?ERRT_INTERNAL_SERVER_ERROR(Lang, ErrText)),
|
||||||
@ -1725,7 +1736,24 @@ check_captcha(Affiliation, From, StateData) ->
|
|||||||
{ok, passed} ->
|
{ok, passed} ->
|
||||||
true;
|
true;
|
||||||
_ ->
|
_ ->
|
||||||
|
WList = (StateData#state.config)#config.captcha_whitelist,
|
||||||
|
#jid{luser = U, lserver = S, lresource = R} = From,
|
||||||
|
case ?SETS:is_element({U, S, R}, WList) of
|
||||||
|
true ->
|
||||||
|
true;
|
||||||
|
false ->
|
||||||
|
case ?SETS:is_element({U, S, ""}, WList) of
|
||||||
|
true ->
|
||||||
|
true;
|
||||||
|
false ->
|
||||||
|
case ?SETS:is_element({"", S, ""}, WList) of
|
||||||
|
true ->
|
||||||
|
true;
|
||||||
|
false ->
|
||||||
captcha_required
|
captcha_required
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
true
|
true
|
||||||
@ -2525,6 +2553,11 @@ can_change_ra(_FAffiliation, _FRole,
|
|||||||
%% A room owner tries to add as persistent owner a
|
%% A room owner tries to add as persistent owner a
|
||||||
%% participant that is already owner because he is MUC admin
|
%% participant that is already owner because he is MUC admin
|
||||||
true;
|
true;
|
||||||
|
can_change_ra(_FAffiliation, _FRole,
|
||||||
|
_TAffiliation, _TRole,
|
||||||
|
_RoleorAffiliation, _Value, owner) ->
|
||||||
|
%% Nobody can decrease MUC admin's role/affiliation
|
||||||
|
false;
|
||||||
can_change_ra(_FAffiliation, _FRole,
|
can_change_ra(_FAffiliation, _FRole,
|
||||||
TAffiliation, _TRole,
|
TAffiliation, _TRole,
|
||||||
affiliation, Value, _ServiceAf)
|
affiliation, Value, _ServiceAf)
|
||||||
@ -2699,14 +2732,21 @@ send_kickban_presence(JID, Reason, Code, NewAffiliation, StateData) ->
|
|||||||
end, LJIDs).
|
end, LJIDs).
|
||||||
|
|
||||||
send_kickban_presence1(UJID, Reason, Code, Affiliation, StateData) ->
|
send_kickban_presence1(UJID, Reason, Code, Affiliation, StateData) ->
|
||||||
{ok, #user{jid = _RealJID,
|
{ok, #user{jid = RealJID,
|
||||||
nick = Nick}} =
|
nick = Nick}} =
|
||||||
?DICT:find(jlib:jid_tolower(UJID), StateData#state.users),
|
?DICT:find(jlib:jid_tolower(UJID), StateData#state.users),
|
||||||
SAffiliation = affiliation_to_list(Affiliation),
|
SAffiliation = affiliation_to_list(Affiliation),
|
||||||
|
BannedJIDString = jlib:jid_to_string(RealJID),
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun({_LJID, Info}) ->
|
fun({_LJID, Info}) ->
|
||||||
|
JidAttrList = case (Info#user.role == moderator) orelse
|
||||||
|
((StateData#state.config)#config.anonymous
|
||||||
|
== false) of
|
||||||
|
true -> [{"jid", BannedJIDString}];
|
||||||
|
false -> []
|
||||||
|
end,
|
||||||
ItemAttrs = [{"affiliation", SAffiliation},
|
ItemAttrs = [{"affiliation", SAffiliation},
|
||||||
{"role", "none"}],
|
{"role", "none"}] ++ JidAttrList,
|
||||||
ItemEls = case Reason of
|
ItemEls = case Reason of
|
||||||
"" ->
|
"" ->
|
||||||
[];
|
[];
|
||||||
@ -2907,6 +2947,13 @@ is_password_settings_correct(XEl, StateData) ->
|
|||||||
-define(PRIVATEXFIELD(Label, Var, Val),
|
-define(PRIVATEXFIELD(Label, Var, Val),
|
||||||
?XFIELD("text-private", Label, Var, Val)).
|
?XFIELD("text-private", Label, Var, Val)).
|
||||||
|
|
||||||
|
-define(JIDMULTIXFIELD(Label, Var, JIDList),
|
||||||
|
{xmlelement, "field", [{"type", "jid-multi"},
|
||||||
|
{"label", translate:translate(Lang, Label)},
|
||||||
|
{"var", Var}],
|
||||||
|
[{xmlelement, "value", [], [{xmlcdata, jlib:jid_to_string(JID)}]}
|
||||||
|
|| JID <- JIDList]}).
|
||||||
|
|
||||||
get_default_room_maxusers(RoomState) ->
|
get_default_room_maxusers(RoomState) ->
|
||||||
DefRoomOpts = gen_mod:get_module_opt(RoomState#state.server_host, mod_muc, default_room_options, []),
|
DefRoomOpts = gen_mod:get_module_opt(RoomState#state.server_host, mod_muc, default_room_options, []),
|
||||||
RoomState2 = set_opts(DefRoomOpts, RoomState),
|
RoomState2 = set_opts(DefRoomOpts, RoomState),
|
||||||
@ -3027,6 +3074,9 @@ get_config(Lang, StateData, From) ->
|
|||||||
Config#config.captcha_protected)];
|
Config#config.captcha_protected)];
|
||||||
false -> []
|
false -> []
|
||||||
end ++
|
end ++
|
||||||
|
[?JIDMULTIXFIELD("Exclude Jabber IDs from CAPTCHA challenge",
|
||||||
|
"muc#roomconfig_captcha_whitelist",
|
||||||
|
?SETS:to_list(Config#config.captcha_whitelist))] ++
|
||||||
case mod_muc_log:check_access_log(
|
case mod_muc_log:check_access_log(
|
||||||
StateData#state.server_host, From) of
|
StateData#state.server_host, From) of
|
||||||
allow ->
|
allow ->
|
||||||
@ -3096,6 +3146,18 @@ set_config(XEl, StateData) ->
|
|||||||
-define(SET_STRING_XOPT(Opt, Val),
|
-define(SET_STRING_XOPT(Opt, Val),
|
||||||
set_xoption(Opts, Config#config{Opt = Val})).
|
set_xoption(Opts, Config#config{Opt = Val})).
|
||||||
|
|
||||||
|
-define(SET_JIDMULTI_XOPT(Opt, Vals),
|
||||||
|
begin
|
||||||
|
Set = lists:foldl(
|
||||||
|
fun({U, S, R}, Set1) ->
|
||||||
|
?SETS:add_element({U, S, R}, Set1);
|
||||||
|
(#jid{luser = U, lserver = S, lresource = R}, Set1) ->
|
||||||
|
?SETS:add_element({U, S, R}, Set1);
|
||||||
|
(_, Set1) ->
|
||||||
|
Set1
|
||||||
|
end, ?SETS:empty(), Vals),
|
||||||
|
set_xoption(Opts, Config#config{Opt = Set})
|
||||||
|
end).
|
||||||
|
|
||||||
set_xoption([], Config) ->
|
set_xoption([], Config) ->
|
||||||
Config;
|
Config;
|
||||||
@ -3153,6 +3215,9 @@ set_xoption([{"muc#roomconfig_maxusers", [Val]} | Opts], Config) ->
|
|||||||
end;
|
end;
|
||||||
set_xoption([{"muc#roomconfig_enablelogging", [Val]} | Opts], Config) ->
|
set_xoption([{"muc#roomconfig_enablelogging", [Val]} | Opts], Config) ->
|
||||||
?SET_BOOL_XOPT(logging, Val);
|
?SET_BOOL_XOPT(logging, Val);
|
||||||
|
set_xoption([{"muc#roomconfig_captcha_whitelist", Vals} | Opts], Config) ->
|
||||||
|
JIDs = [jlib:string_to_jid(Val) || Val <- Vals],
|
||||||
|
?SET_JIDMULTI_XOPT(captcha_whitelist, JIDs);
|
||||||
set_xoption([{"FORM_TYPE", _} | Opts], Config) ->
|
set_xoption([{"FORM_TYPE", _} | Opts], Config) ->
|
||||||
%% Ignore our FORM_TYPE
|
%% Ignore our FORM_TYPE
|
||||||
set_xoption(Opts, Config);
|
set_xoption(Opts, Config);
|
||||||
@ -3222,6 +3287,7 @@ set_opts([{Opt, Val} | Opts], StateData) ->
|
|||||||
password -> StateData#state{config = (StateData#state.config)#config{password = Val}};
|
password -> StateData#state{config = (StateData#state.config)#config{password = Val}};
|
||||||
anonymous -> StateData#state{config = (StateData#state.config)#config{anonymous = Val}};
|
anonymous -> StateData#state{config = (StateData#state.config)#config{anonymous = Val}};
|
||||||
logging -> StateData#state{config = (StateData#state.config)#config{logging = Val}};
|
logging -> StateData#state{config = (StateData#state.config)#config{logging = Val}};
|
||||||
|
captcha_whitelist -> StateData#state{config = (StateData#state.config)#config{captcha_whitelist = ?SETS:from_list(Val)}};
|
||||||
max_users ->
|
max_users ->
|
||||||
ServiceMaxUsers = get_service_max_users(StateData),
|
ServiceMaxUsers = get_service_max_users(StateData),
|
||||||
MaxUsers = if
|
MaxUsers = if
|
||||||
@ -3266,6 +3332,8 @@ make_opts(StateData) ->
|
|||||||
?MAKE_CONFIG_OPT(anonymous),
|
?MAKE_CONFIG_OPT(anonymous),
|
||||||
?MAKE_CONFIG_OPT(logging),
|
?MAKE_CONFIG_OPT(logging),
|
||||||
?MAKE_CONFIG_OPT(max_users),
|
?MAKE_CONFIG_OPT(max_users),
|
||||||
|
{captcha_whitelist,
|
||||||
|
?SETS:to_list((StateData#state.config)#config.captcha_whitelist)},
|
||||||
{affiliations, ?DICT:to_list(StateData#state.affiliations)},
|
{affiliations, ?DICT:to_list(StateData#state.affiliations)},
|
||||||
{subject, StateData#state.subject},
|
{subject, StateData#state.subject},
|
||||||
{subject_author, StateData#state.subject_author}
|
{subject_author, StateData#state.subject_author}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
@ -45,7 +45,8 @@
|
|||||||
password = "",
|
password = "",
|
||||||
anonymous = true,
|
anonymous = true,
|
||||||
max_users = ?MAX_USERS_DEFAULT,
|
max_users = ?MAX_USERS_DEFAULT,
|
||||||
logging = false
|
logging = false,
|
||||||
|
captcha_whitelist = ?SETS:empty()
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-record(user, {jid,
|
-record(user, {jid,
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 5 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 5 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 5 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
%%% Created : 5 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%%% Created : 11 Jul 2009 by Brian Cully <bjc@kublai.com>
|
%%% Created : 11 Jul 2009 by Brian Cully <bjc@kublai.com>
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
|
||||||
%%%
|
%%%
|
||||||
%%% This program is free software; you can redistribute it and/or
|
%%% This program is free software; you can redistribute it and/or
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
%%% modify it under the terms of the GNU General Public License as
|
||||||
@ -95,7 +95,7 @@ init([Host, Opts]) ->
|
|||||||
SendPings = gen_mod:get_opt(send_pings, Opts, ?DEFAULT_SEND_PINGS),
|
SendPings = gen_mod:get_opt(send_pings, Opts, ?DEFAULT_SEND_PINGS),
|
||||||
PingInterval = gen_mod:get_opt(ping_interval, Opts, ?DEFAULT_PING_INTERVAL),
|
PingInterval = gen_mod:get_opt(ping_interval, Opts, ?DEFAULT_PING_INTERVAL),
|
||||||
TimeoutAction = gen_mod:get_opt(timeout_action, Opts, none),
|
TimeoutAction = gen_mod:get_opt(timeout_action, Opts, none),
|
||||||
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
|
IQDisc = gen_mod:get_opt(iqdisc, Opts, no_queue),
|
||||||
mod_disco:register_feature(Host, ?NS_PING),
|
mod_disco:register_feature(Host, ?NS_PING),
|
||||||
gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_PING,
|
gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_PING,
|
||||||
?MODULE, iq_ping, IQDisc),
|
?MODULE, iq_ping, IQDisc),
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user