24
1
mirror of https://github.com/processone/ejabberd.git synced 2024-07-02 23:06:21 +02:00

fix merge conflicts from 2.1.9

This commit is contained in:
Christophe Romain 2011-09-30 14:28:40 +02:00
commit adf56dedf3
47 changed files with 677 additions and 314 deletions

View File

@ -2,7 +2,7 @@
"http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML>
<HEAD>
<TITLE>Ejabberd 2.1.7 Developers Guide
<TITLE>Ejabberd 2.1.9 Developers Guide
</TITLE>
<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
@ -49,7 +49,7 @@ TD P{margin:0px;}
<!--HEVEA command line is: /usr/bin/hevea -fix -pedantic dev.tex -->
<!--CUT DEF section 1 --><P><A NAME="titlepage"></A>
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.7 Developers Guide</H1><H3 CLASS="titlerest">Alexey Shchepin<BR>
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.9 Developers Guide</H1><H3 CLASS="titlerest">Alexey Shchepin<BR>
<A HREF="mailto:alexey@sevcom.net"><TT>mailto:alexey@sevcom.net</TT></A><BR>
<A HREF="xmpp:aleksey@jabber.ru"><TT>xmpp:aleksey@jabber.ru</TT></A></H3></TD></TR>
</TABLE><DIV CLASS="center">

View File

@ -2,7 +2,7 @@
"http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML>
<HEAD>
<TITLE>Ejabberd 2.1.7 Feature Sheet
<TITLE>Ejabberd 2.1.9 Feature Sheet
</TITLE>
<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
@ -50,7 +50,7 @@ SPAN{width:20%; float:right; text-align:left; margin-left:auto;}
<!--HEVEA command line is: /usr/bin/hevea -fix -pedantic features.tex -->
<!--CUT DEF section 1 --><P><A NAME="titlepage"></A>
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.7 Feature Sheet</H1><H3 CLASS="titlerest">Sander Devrieze<BR>
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.9 Feature Sheet</H1><H3 CLASS="titlerest">Sander Devrieze<BR>
<A HREF="mailto:s.devrieze@pandora.be"><TT>mailto:s.devrieze@pandora.be</TT></A><BR>
<A HREF="xmpp:sander@devrieze.dyndns.org"><TT>xmpp:sander@devrieze.dyndns.org</TT></A></H3></TD></TR>
</TABLE><DIV CLASS="center">

View File

@ -6,7 +6,7 @@
ejabberd 2.1.7
ejabberd 2.1.9
Installation and Operation Guide
@ -76,7 +76,7 @@ BLOCKQUOTE.figure DIV.center DIV.center HR{display:none;}
<HR SIZE=2><BR>
<BR>
<TABLE CELLSPACING=6 CELLPADDING=0><TR><TD ALIGN=right NOWRAP> <FONT SIZE=6><B>ejabberd 2.1.7 </B></FONT></TD></TR>
<TABLE CELLSPACING=6 CELLPADDING=0><TR><TD ALIGN=right NOWRAP> <FONT SIZE=6><B>ejabberd 2.1.9 </B></FONT></TD></TR>
<TR><TD ALIGN=right NOWRAP>&nbsp;</TD></TR>
<TR><TD ALIGN=right NOWRAP> <FONT SIZE=6>Installation and Operation Guide</FONT></TD></TR>
</TABLE><BR>
@ -306,8 +306,9 @@ Note that the Windows service is a feature still in development,
and for example it doesn&#X2019;t read the file ejabberdctl.cfg.</P><P>On a *nix system, if you want ejabberd to be started as daemon at boot time,
copy <TT>ejabberd.init</TT> from the &#X2019;bin&#X2019; directory to something like <TT>/etc/init.d/ejabberd</TT>
(depending on your distribution).
Create a system user called <TT>ejabberd</TT>;
it will be used by the script to start the server.
Create a system user called <TT>ejabberd</TT>,
give it write access to the directories <TT>database/</TT> and <TT>logs/</TT>, and set that as home;
the script will start the server with that user.
Then you can call <TT>/etc/inid.d/ejabberd start</TT> as root to start the server.</P><P>If <TT>ejabberd</TT> doesn&#X2019;t start correctly in Windows,
try to start it using the shortcut in desktop or start menu.
If the window shows error 14001, the solution is to install:
@ -525,8 +526,8 @@ Using <TT>ejabberdctl</TT> (see section&#XA0;<A HREF="#ejabberdctl">4.1</A>):
</PRE></LI><LI CLASS="li-enumerate">Using a XMPP client and In-Band Registration (see section&#XA0;<A HREF="#modregister">3.3.19</A>).
</LI></OL>
</LI><LI CLASS="li-enumerate">Edit the <TT>ejabberd</TT> configuration file to give administration rights to the XMPP account you created:
<PRE CLASS="verbatim">{acl, admins, {user, "admin1", "example.org"}}.
{access, configure, [{allow, admins}]}.
<PRE CLASS="verbatim">{acl, admin, {user, "admin1", "example.org"}}.
{access, configure, [{allow, admin}]}.
</PRE>You can grant administrative privileges to many XMPP accounts,
and also to accounts in other XMPP servers.
</LI><LI CLASS="li-enumerate">Restart <TT>ejabberd</TT> to load the new configuration.
@ -1051,17 +1052,40 @@ internal (default) &#X2014; See section&#XA0;<A HREF="#internalauth">3.1.4</A>.
<A HREF="#mssql">3.2.2</A> and <A HREF="#odbc">3.2.4</A>.
</LI><LI CLASS="li-itemize">anonymous &#X2014; See section&#XA0;<A HREF="#saslanonymous">3.1.4</A>.
</LI><LI CLASS="li-itemize">pam &#X2014; See section&#XA0;<A HREF="#pam">3.1.4</A>.
</LI></UL><P>Account creation is only supported by internal, external and odbc methods.</P><P> <A NAME="internalauth"></A> </P><!--TOC subsubsection Internal-->
</LI></UL><P>Account creation is only supported by internal, external and odbc methods.</P><P>The option <TT>resource_conflict</TT> defines the action when a client attempts to
login to an account with a resource that is already connected.
The option syntax is:
</P><DL CLASS="description"><DT CLASS="dt-description"><B><TT>{resource_conflict, setresource|closenew|closeold}.</TT></B></DT></DL><P>
The possible values match exactly the three possibilities described in
<A HREF="http://tools.ietf.org/html/rfc6120#section-7.7.2.2">XMPP Core: section 7.7.2.2</A>.
The default value is <TT>closeold</TT>.
If the client uses old Jabber Non-SASL authentication (<A HREF="http://xmpp.org/extensions/xep-0078.html">XEP-0078</A>),
then this option is not respected, and the action performed is <TT>closeold</TT>.</P><P> <A NAME="internalauth"></A> </P><!--TOC subsubsection Internal-->
<H4 CLASS="subsubsection"><!--SEC ANCHOR --><A HREF="#internalauth">Internal</A></H4><!--SEC END --><P> <A NAME="internalauth"></A>
</P><P><TT>ejabberd</TT> uses its internal Mnesia database as the default authentication method.
The value <TT>internal</TT> will enable the internal authentication method.</P><P>Examples:
The value <TT>internal</TT> will enable the internal authentication method.</P><P>The option <TT>{auth_password_format, plain|scram}</TT>
defines in what format the users passwords are stored:
</P><DL CLASS="description"><DT CLASS="dt-description">
<B><TT>plain</TT></B></DT><DD CLASS="dd-description">
The password is stored as plain text in the database.
This is risky because the passwords can be read if your database gets compromised.
This is the default value.
This format allows clients to authenticate using:
the old Jabber Non-SASL (<A HREF="http://xmpp.org/extensions/xep-0078.html">XEP-0078</A>), <TT>SASL PLAIN</TT>,
<TT>SASL DIGEST-MD5</TT>, and <TT>SASL SCRAM-SHA-1</TT>.</DD><DT CLASS="dt-description"><B><TT>scram</TT></B></DT><DD CLASS="dd-description">
The password is not stored, only some information that allows to verify the hash provided by the client.
It is impossible to obtain the original plain password from the stored information;
for this reason, when this value is configured it cannot be changed to <TT>plain</TT> anymore.
This format allows clients to authenticate using: <TT>SASL PLAIN</TT> and <TT>SASL SCRAM-SHA-1</TT>.
</DD></DL><P>Examples:
</P><UL CLASS="itemize"><LI CLASS="li-itemize">
To use internal authentication on <TT>example.org</TT> and LDAP
authentication on <TT>example.net</TT>:
<PRE CLASS="verbatim">{host_config, "example.org", [{auth_method, [internal]}]}.
{host_config, "example.net", [{auth_method, [ldap]}]}.
</PRE></LI><LI CLASS="li-itemize">To use internal authentication on all virtual hosts:
</PRE></LI><LI CLASS="li-itemize">To use internal authentication with hashed passwords on all virtual hosts:
<PRE CLASS="verbatim">{auth_method, internal}.
{auth_password_format, scram}.
</PRE></LI></UL><P> <A NAME="extauth"></A> </P><!--TOC subsubsection External Script-->
<H4 CLASS="subsubsection"><!--SEC ANCHOR --><A HREF="#extauth">External Script</A></H4><!--SEC END --><P> <A NAME="extauth"></A>
</P><P>In this authentication method, when <TT>ejabberd</TT> starts,
@ -1208,9 +1232,9 @@ declarations of ACLs in the configuration file have the following syntax:
</PRE></DD><DT CLASS="dt-description"><B><TT>{user_regexp, Regexp}</TT></B></DT><DD CLASS="dd-description"> Matches any local user with a name that
matches <TT>Regexp</TT> on local virtual hosts. Example:
<PRE CLASS="verbatim">{acl, tests, {user_regexp, "^test[0-9]*$"}}.
</PRE></DD><DT CLASS="dt-description"><B><TT>{user_regexp, UserRegexp, Server}</TT></B></DT><DD CLASS="dd-description"> Matches any user with a name
</PRE></DD><DT CLASS="dt-description"><B><TT>{user_regexp, Regexp, Server}</TT></B></DT><DD CLASS="dd-description"> Matches any user with a name
that matches <TT>Regexp</TT> at server <TT>Server</TT>. Example:
<PRE CLASS="verbatim">{acl, tests, {user_Userregexp, "^test", "example.org"}}.
<PRE CLASS="verbatim">{acl, tests, {user_regexp, "^test", "example.org"}}.
</PRE></DD><DT CLASS="dt-description"><B><TT>{server_regexp, Regexp}</TT></B></DT><DD CLASS="dd-description"> Matches any JID from the server that
matches <TT>Regexp</TT>. Example:
<PRE CLASS="verbatim">{acl, icq, {server_regexp, "^icq\\."}}.
@ -1701,6 +1725,16 @@ This option specifies whether to verify LDAP server certificate or not when TLS
When <TT>hard</TT> is enabled <TT>ejabberd</TT> doesn&#X2019;t proceed if a certificate is invalid.
When <TT>soft</TT> is enabled <TT>ejabberd</TT> proceeds even if check fails.
The default is <TT>false</TT> which means no checks are performed.
</DD><DT CLASS="dt-description"><B><TT>{ldap_tls_cacertfile, Path}</TT></B></DT><DD CLASS="dd-description">
Path to file containing PEM encoded CA certificates. This option is needed
(and required) when TLS verification is enabled.
</DD><DT CLASS="dt-description"><B><TT>{ldap_tls_depth, Number}</TT></B></DT><DD CLASS="dd-description">
Specifies the maximum verification depth when TLS verification is enabled,
i.e. how far in a chain of certificates the verification process can proceed
before the verification is considered to fail.
Peer certificate = 0, CA certificate = 1, higher level CA certificate = 2, etc.
The value 2 thus means that a chain can at most contain peer cert,
CA cert, next CA cert, and an additional CA cert. The default value is 1.
</DD><DT CLASS="dt-description"><B><TT>{ldap_port, Number}</TT></B></DT><DD CLASS="dd-description"> Port to connect to your LDAP server.
The default port is&#XA0;389 if encryption is disabled; and 636 if encryption is enabled.
If you configure a value, it is stored in <TT>ejabberd</TT>&#X2019;s database.
@ -1710,6 +1744,7 @@ the value previously stored in the database will be used instead of the default
is&#XA0;<TT>""</TT> which means &#X2018;anonymous connection&#X2019;.
</DD><DT CLASS="dt-description"><B><TT>{ldap_password, Password}</TT></B></DT><DD CLASS="dd-description"> Bind password. The default
value is <TT>""</TT>.
</DD><DT CLASS="dt-description"><B><TT>{ldap_deref_aliases, never|always|finding|searching}</TT></B></DT><DD CLASS="dd-description"> Whether or not to dereference aliases. The default is <TT>never</TT>.
</DD></DL><P>Example:
</P><PRE CLASS="verbatim">{auth_method, ldap}.
{ldap_servers, ["ldap.example.org"]}.
@ -1931,7 +1966,7 @@ all entries end with a comma:
<TR><TD ALIGN=left NOWRAP><A HREF="#modoffline"><TT>mod_offline</TT></A></TD><TD ALIGN=left NOWRAP>Offline message storage (<A HREF="http://xmpp.org/extensions/xep-0160.html">XEP-0160</A>)</TD><TD ALIGN=left NOWRAP>&nbsp;</TD></TR>
<TR><TD ALIGN=left NOWRAP><A HREF="#modoffline"><TT>mod_offline_odbc</TT></A></TD><TD ALIGN=left NOWRAP>Offline message storage (<A HREF="http://xmpp.org/extensions/xep-0160.html">XEP-0160</A>)</TD><TD ALIGN=left NOWRAP>supported DB (*)</TD></TR>
<TR><TD ALIGN=left NOWRAP><A HREF="#modping"><TT>mod_ping</TT></A></TD><TD ALIGN=left NOWRAP>XMPP Ping and periodic keepalives (<A HREF="http://xmpp.org/extensions/xep-0199.html">XEP-0199</A>)</TD><TD ALIGN=left NOWRAP>&nbsp;</TD></TR>
<TR><TD ALIGN=left NOWRAP><A HREF="#modprescounter"><TT>mod_privacy</TT></A></TD><TD ALIGN=left NOWRAP>Detect presence subscription flood</TD><TD ALIGN=left NOWRAP>&nbsp;</TD></TR>
<TR><TD ALIGN=left NOWRAP><A HREF="#modprescounter"><TT>mod_pres_counter</TT></A></TD><TD ALIGN=left NOWRAP>Detect presence subscription flood</TD><TD ALIGN=left NOWRAP>&nbsp;</TD></TR>
<TR><TD ALIGN=left NOWRAP><A HREF="#modprivacy"><TT>mod_privacy</TT></A></TD><TD ALIGN=left NOWRAP>Blocking Communication (<A HREF="http://xmpp.org/extensions/xep-0016.html">XEP-0016</A>)</TD><TD ALIGN=left NOWRAP>&nbsp;</TD></TR>
<TR><TD ALIGN=left NOWRAP><A HREF="#modprivacy"><TT>mod_privacy_odbc</TT></A></TD><TD ALIGN=left NOWRAP>Blocking Communication (<A HREF="http://xmpp.org/extensions/xep-0016.html">XEP-0016</A>)</TD><TD ALIGN=left NOWRAP>supported DB (*)</TD></TR>
<TR><TD ALIGN=left NOWRAP><A HREF="#modprivate"><TT>mod_private</TT></A></TD><TD ALIGN=left NOWRAP>Private XML Storage (<A HREF="http://xmpp.org/extensions/xep-0049.html">XEP-0049</A>)</TD><TD ALIGN=left NOWRAP>&nbsp;</TD></TR>
@ -2077,7 +2112,7 @@ able to send such messages).
</DD></DL><P>Examples:
</P><UL CLASS="itemize"><LI CLASS="li-itemize">
Only administrators can send announcements:
<PRE CLASS="verbatim">{access, announce, [{allow, admins}]}.
<PRE CLASS="verbatim">{access, announce, [{allow, admin}]}.
{modules,
[
@ -2089,9 +2124,9 @@ Only administrators can send announcements:
</PRE></LI><LI CLASS="li-itemize">Administrators as well as the direction can send announcements:
<PRE CLASS="verbatim">{acl, direction, {user, "big_boss", "example.org"}}.
{acl, direction, {user, "assistant", "example.org"}}.
{acl, admins, {user, "admin", "example.org"}}.
{acl, admin, {user, "admin", "example.org"}}.
{access, announce, [{allow, admins},
{access, announce, [{allow, admin},
{allow, direction}]}.
{modules,
@ -2497,6 +2532,7 @@ The available room options and the default values are:
<DL CLASS="description"><DT CLASS="dt-description">
<B><TT>{allow_change_subj, true|false}</TT></B></DT><DD CLASS="dd-description"> Allow occupants to change the subject.
</DD><DT CLASS="dt-description"><B><TT>{allow_private_messages, true|false}</TT></B></DT><DD CLASS="dd-description"> Occupants can send private messages to other occupants.
</DD><DT CLASS="dt-description"><B><TT>{allow_private_messages_from_visitors, anyone|moderators|nobody}</TT></B></DT><DD CLASS="dd-description"> Visitors can send private messages to other occupants.
</DD><DT CLASS="dt-description"><B><TT>{allow_query_users, true|false}</TT></B></DT><DD CLASS="dd-description"> Occupants can send IQ queries to other occupants.
</DD><DT CLASS="dt-description"><B><TT>{allow_user_invites, false|true}</TT></B></DT><DD CLASS="dd-description"> Allow occupants to send invitations.
</DD><DT CLASS="dt-description"><B><TT>{allow_visitor_nickchange, true|false}</TT></B></DT><DD CLASS="dd-description"> Allow visitors to
@ -2715,10 +2751,10 @@ used. The names of the log files will only contain the day (number),
and there will be subdirectories for each year and month. The log files will
be stored in /var/www/muclogs, and the local time will be used. Finally, the
top link will be the default <CODE>&lt;a href="/"&gt;Home&lt;/a&gt;</CODE>.
<PRE CLASS="verbatim">{acl, admins, {user, "admin1", "example.org"}}.
{acl, admins, {user, "admin2", "example.net"}}.
<PRE CLASS="verbatim">{acl, admin, {user, "admin1", "example.org"}}.
{acl, admin, {user, "admin2", "example.net"}}.
{access, muc_log, [{allow, admins},
{access, muc_log, [{allow, admin},
{deny, all}]}.
{modules,
@ -3115,7 +3151,9 @@ To enable this feature, configure the options captcha_cmd and captcha_host.</P><
<B><TT>{registration_watchers, [ JID, ...]}</TT></B></DT><DD CLASS="dd-description"> This option defines a
list of JIDs which will be notified each time a new account is registered.
</DD></DL><P>This example configuration shows how to enable the module and the web handler:
</P><PRE CLASS="verbatim">{listen, [
</P><PRE CLASS="verbatim">{hosts, ["localhost", "example.org", "example.com"]}.
{listen, [
...
{5281, ejabberd_http, [
tls,
@ -3131,7 +3169,8 @@ list of JIDs which will be notified each time a new account is registered.
{mod_register_web, []},
...
]}.
</PRE><P>The users can visit this page: https://localhost:5281/register/
</PRE><P>For example, the users of the host <TT>example.org</TT> can visit the page:
<TT>https://example.org:5281/register/</TT>
It is important to include the last / character in the URL,
otherwise the subpages URL will be incorrect.</P><P> <A NAME="modroster"></A> </P><!--TOC subsection <TT>mod_roster</TT>-->
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc59">3.3.21</A>&#XA0;&#XA0;<A HREF="#modroster"><TT>mod_roster</TT></A></H3><!--SEC END --><P> <A NAME="modroster"></A>
@ -3598,8 +3637,9 @@ and LDAP server supports
its own optional parameters. The first group of parameters has the same
meaning as the top-level LDAP parameters to set the authentication method:
<TT>ldap_servers</TT>, <TT>ldap_port</TT>, <TT>ldap_rootdn</TT>,
<TT>ldap_password</TT>, <TT>ldap_base</TT>, <TT>ldap_uids</TT>, and
<TT>ldap_filter</TT>. See section&#XA0;<A HREF="#ldapauth">3.2.5</A> for detailed information
<TT>ldap_password</TT>, <TT>ldap_base</TT>, <TT>ldap_uids</TT>,
<TT>ldap_deref_aliases</TT> and <TT>ldap_filter</TT>.
See section&#XA0;<A HREF="#ldapauth">3.2.5</A> for detailed information
about these options. If one of these options is not set, <TT>ejabberd</TT> will look
for the top-level option with the same name.</P><P>The second group of parameters
consists of the following <TT>mod_vcard_ldap</TT>-specific options:</P><DL CLASS="description"><DT CLASS="dt-description">
@ -3865,6 +3905,8 @@ all the environment variables and command line parameters.</P><P>The environment
This path is used to read the file <TT>.erlang.cookie</TT>.
</DD><DT CLASS="dt-description"><B><TT>ERL_CRASH_DUMP</TT></B></DT><DD CLASS="dd-description">
Path to the file where crash reports will be dumped.
</DD><DT CLASS="dt-description"><B><TT>ERL_EPMD_ADDRESS</TT></B></DT><DD CLASS="dd-description">
IP address where epmd listens for connections (see section <A HREF="#epmd">5.2</A>).
</DD><DT CLASS="dt-description"><B><TT>ERL_INETRC</TT></B></DT><DD CLASS="dd-description">
Indicates which IP name resolution to use.
If using <TT>-sname</TT>, specify either this option or <TT>-kernel inetrc filepath</TT>.
@ -3891,10 +3933,10 @@ This is only useful if you plan to setup an <TT>ejabberd</TT> cluster with nodes
connections (see section <A HREF="#epmd">5.2</A>).
</DD><DT CLASS="dt-description"><B><TT>-detached</TT></B></DT><DD CLASS="dd-description">
Starts the Erlang system detached from the system console.
Useful for running daemons and backgrounds processes.
Useful for running daemons and background processes.
</DD><DT CLASS="dt-description"><B><TT>-noinput</TT></B></DT><DD CLASS="dd-description">
Ensures that the Erlang system never tries to read any input.
Useful for running daemons and backgrounds processes.
Useful for running daemons and background processes.
</DD><DT CLASS="dt-description"><B><TT>-pa /var/lib/ejabberd/ebin</TT></B></DT><DD CLASS="dd-description">
Specify the directory where Erlang binary files (*.beam) are located.
</DD><DT CLASS="dt-description"><B><TT>-s ejabberd</TT></B></DT><DD CLASS="dd-description">
@ -4059,11 +4101,11 @@ URL). If you log in with &#X2018;<TT>admin@example.com</TT>&#X2019; on<BR>
<CODE>http://example.org:5280/admin/server/example.com/</CODE> you can only
administer the virtual host <TT>example.com</TT>.
The account &#X2018;<TT>reviewer@example.com</TT>&#X2019; can browse that vhost in read-only mode.
<PRE CLASS="verbatim">{acl, admins, {user, "admin", "example.net"}}.
{host_config, "example.com", [{acl, admins, {user, "admin", "example.com"}}]}.
<PRE CLASS="verbatim">{acl, admin, {user, "admin", "example.net"}}.
{host_config, "example.com", [{acl, admin, {user, "admin", "example.com"}}]}.
{host_config, "example.com", [{acl, viewers, {user, "reviewer", "example.com"}}]}.
{access, configure, [{allow, admins}]}.
{access, configure, [{allow, admin}]}.
{access, webadmin_view, [{allow, viewers}]}.
{hosts, ["example.org"]}.
@ -4178,7 +4220,9 @@ and connects to the Erlang node that holds <TT>ejabberd</TT>.
In order for this communication to work,
<TT>epmd</TT> must be running and listening for name requests in the port 4369.
You should block the port 4369 in the firewall in such a way that
only the programs in your machine can access it.</P><P>If you build a cluster of several <TT>ejabberd</TT> instances,
only the programs in your machine can access it.
or configure the option <TT>ERL_EPMD_ADDRESS</TT> in the file <TT>ejabberdctl.cfg</TT>
(this option works only in Erlang/OTP R14B03 or higher).</P><P>If you build a cluster of several <TT>ejabberd</TT> instances,
each <TT>ejabberd</TT> instance is called an <TT>ejabberd</TT> node.
Those <TT>ejabberd</TT> nodes use a special Erlang communication method to
build the cluster, and EPMD is again needed listening in the port 4369.

View File

@ -250,8 +250,9 @@ and for example it doesn't read the file ejabberdctl.cfg.
On a *nix system, if you want ejabberd to be started as daemon at boot time,
copy \term{ejabberd.init} from the 'bin' directory to something like \term{/etc/init.d/ejabberd}
(depending on your distribution).
Create a system user called \term{ejabberd};
it will be used by the script to start the server.
Create a system user called \term{ejabberd},
give it write access to the directories \term{database/} and \term{logs/}, and set that as home;
the script will start the server with that user.
Then you can call \term{/etc/inid.d/ejabberd start} as root to start the server.
If \term{ejabberd} doesn't start correctly in Windows,
@ -1489,10 +1490,10 @@ declarations of ACLs in the configuration file have the following syntax:
{acl, tests, {user_regexp, "^test[0-9]*$"}}.
\end{verbatim}
%$
\titem{\{user\_regexp, UserRegexp, Server\}} Matches any user with a name
\titem{\{user\_regexp, Regexp, Server\}} Matches any user with a name
that matches \term{Regexp} at server \term{Server}. Example:
\begin{verbatim}
{acl, tests, {user_Userregexp, "^test", "example.org"}}.
{acl, tests, {user_regexp, "^test", "example.org"}}.
\end{verbatim}
\titem{\{server\_regexp, Regexp\}} Matches any JID from the server that
matches \term{Regexp}. Example:
@ -2311,6 +2312,7 @@ the value previously stored in the database will be used instead of the default
is~\term{""} which means `anonymous connection'.
\titem{\{ldap\_password, Password\}} \ind{options!ldap\_password}Bind password. The default
value is \term{""}.
\titem{\{ldap\_deref\_aliases, never|always|finding|searching\}} \ind{options!ldap\_deref\_aliases} Whether or not to dereference aliases. The default is \term{never}.
\end{description}
Example:
@ -4697,8 +4699,9 @@ The \modvcardldap{} module has
its own optional parameters. The first group of parameters has the same
meaning as the top-level LDAP parameters to set the authentication method:
\option{ldap\_servers}, \option{ldap\_port}, \option{ldap\_rootdn},
\option{ldap\_password}, \option{ldap\_base}, \option{ldap\_uids}, and
\option{ldap\_filter}. See section~\ref{ldapauth} for detailed information
\option{ldap\_password}, \option{ldap\_base}, \option{ldap\_uids},
\option{ldap\_deref\_aliases} and \option{ldap\_filter}.
See section~\ref{ldapauth} for detailed information
about these options. If one of these options is not set, \ejabberd{} will look
for the top-level option with the same name.

View File

@ -0,0 +1,56 @@
Release Notes
ejabberd 2.1.9
ejabberd 2.1.9 is the eighth release in ejabberd 2.1.x branch,
and includes a lot of bugfixes and improvements.
Read more details about the changes in:
http://redir.process-one.net/ejabberd-2.1.9
Download the source code and installers from:
http://www.process-one.net/en/ejabberd/
The changes are:
* Core ejabberd
- Decrease CPU usage caused by tls:send with large data
- Escape iolist correctly when NIFs are disabled (EJAB-1462)
- Fix code to satisfy Dialyzer warnings
- Fix compilation in Windows
- Replace calls of OTP's Binary, since they would require R14
* LDAP
- Document ldap_tls_cacertfile and ldap_tls_depth options (EJAB-1299)
- Log an error when an LDAP filter is incorrect (EJAB-1395)
- New options: ldap_tls_cacertfile and ldap_tls_depth (EJAB-1299)
- New option: ldap_deref_aliases (EJAB-639)
- Match ldap_uidattr_format case-insensitively (EJAB-1449)
* MUC
- Support for multiple entry with same nick to MUC rooms (EJAB-305)
- Support voice request and approvement
- New room option: allow_private_messages_from_visitors
- New room options: allow_voice_requests and voice_request_min_interval
- Include status 110 in presence to new occupant (EJAB-740)
- Fix mod_muc_log crash when first log entry is room destroy (EJAB-1499)
- Many fixes and improvements in mod_muc
* Pubsub
- Enable pubsub#deliver_notification checking (EJAB-1453)
- Fix Denial of Service when user sends malformed publish stanza (EJAB-1498)
* ODBC
- Fix ODBC account counting (EJAB-1491)
- Optimized mod_roster_odbc:get_roster
* Miscellanea:
- New SASL SCRAM-SHA-1 authentication mechanism (EJAB-1196)
- New option: resource_conflict (EJAB-650)
Bug reports
You can officially report bugs on ProcessOne support site:
http://support.process-one.net/

View File

@ -1,2 +1,2 @@
% ejabberd version (automatically generated).
\newcommand{\version}{2.1.7}
\newcommand{\version}{2.1.9}

View File

@ -55,6 +55,8 @@ mech_step(#state{step = 2} = State, ClientIn) ->
case string:tokens(ClientIn, ",") of
[CBind, UserNameAttribute, ClientNonceAttribute] when (CBind == "y") or (CBind == "n") ->
case parse_attribute(UserNameAttribute) of
{error, Reason} ->
{error, Reason};
{_, EscapedUserName} ->
case unescape_username(EscapedUserName) of
error ->
@ -89,11 +91,7 @@ mech_step(#state{step = 2} = State, ClientIn) ->
_Else ->
{error, "not-supported"}
end
end;
{error, Reason} ->
{error, Reason};
_Else ->
{error, "bad-protocol"}
end
end;
_Else ->
{error, "bad-protocol"}
@ -139,18 +137,14 @@ mech_step(#state{step = 4} = State, ClientIn) ->
parse_attribute(Attribute) ->
AttributeLen = string:len(Attribute),
if
AttributeLen > 3 ->
AttributeLen >= 3 ->
SecondChar = lists:nth(2, Attribute),
case is_alpha(lists:nth(1, Attribute)) of
true ->
if
SecondChar == $= ->
case string:substr(Attribute, 3) of
String when is_list(String) ->
{lists:nth(1, Attribute), String};
_Else ->
{error, "bad-format failed"}
end;
String = string:substr(Attribute, 3),
{lists:nth(1, Attribute), String};
true ->
{error, "bad-format second char not equal sign"}
end;

View File

@ -2,7 +2,7 @@
{application, ejabberd,
[{description, "ejabberd"},
{vsn, "2.2.x"},
{vsn, "2.2.9"},
{modules, [acl,
adhoc,
configure,

View File

@ -478,7 +478,7 @@ restore(Path) ->
%% Obsolete tables or tables created by module who are no longer used are not
%% restored and are ignored.
keep_tables() ->
lists:flatten([acl, passwd, config, local_config, disco_publish,
lists:flatten([acl, passwd, config, local_config,
keep_modules_tables()]).
%% Returns the list of modules tables in use, according to the list of actually

View File

@ -114,7 +114,7 @@ init() ->
ok -> ok;
{error, already_loaded} -> ok
end,
Port = open_port({spawn, expat_erl}, [binary]),
Port = open_port({spawn, "expat_erl"}, [binary]),
loop(Port).

View File

@ -306,19 +306,16 @@ is_user_exists_in_other_modules_loop([AuthModule|AuthModules], User, Server) ->
end.
%% @spec (User, Server) -> ok | error | {error, not_allowed}
%% @spec (User, Server) -> ok
%% @doc Remove user.
%% Note: it may return ok even if there was some problem removing the user.
remove_user(User, Server) ->
R = lists:foreach(
lists:foreach(
fun(M) ->
M:remove_user(User, Server)
end, auth_modules(Server)),
case R of
ok -> ejabberd_hooks:run(remove_user, jlib:nameprep(Server), [User, Server]);
_ -> none
end,
R.
ejabberd_hooks:run(remove_user, jlib:nameprep(Server), [User, Server]),
ok.
%% @spec (User, Server, Password) -> ok | not_exists | not_allowed | bad_request | error
%% @doc Try to remove user if the provided password is correct.

View File

@ -75,6 +75,7 @@
ufilter,
sfilter,
lfilter, %% Local filter (performed by ejabberd, not LDAP)
deref_aliases,
dn_filter,
dn_filter_attrs
}).
@ -230,10 +231,12 @@ get_vh_registered_users_ldap(Server) ->
ResAttrs = result_attrs(State),
case eldap_filter:parse(State#state.sfilter) of
{ok, EldapFilter} ->
case eldap_pool:search(Eldap_ID, [{base, State#state.base},
{filter, EldapFilter},
{timeout, ?LDAP_SEARCH_TIMEOUT},
{attributes, ResAttrs}]) of
case eldap_pool:search(Eldap_ID,
[{base, State#state.base},
{filter, EldapFilter},
{timeout, ?LDAP_SEARCH_TIMEOUT},
{deref_aliases, State#state.deref_aliases},
{attributes, ResAttrs}]) of
#eldap_search_result{entries = Entries} ->
lists:flatmap(
fun(#eldap_entry{attributes = Attrs,
@ -285,6 +288,7 @@ find_user_dn(User, State) ->
case eldap_pool:search(State#state.eldap_id,
[{base, State#state.base},
{filter, Filter},
{deref_aliases, State#state.deref_aliases},
{attributes, ResAttrs}]) of
#eldap_search_result{entries = [#eldap_entry{attributes = Attrs,
object_name = DN} | _]} ->
@ -322,10 +326,11 @@ is_valid_dn(DN, Attrs, State) ->
end ++ [{"%d", State#state.host}, {"%D", DN}],
case eldap_filter:parse(State#state.dn_filter, SubstValues) of
{ok, EldapFilter} ->
case eldap_pool:search(State#state.eldap_id, [
{base, State#state.base},
{filter, EldapFilter},
{attributes, ["dn"]}]) of
case eldap_pool:search(State#state.eldap_id,
[{base, State#state.base},
{filter, EldapFilter},
{deref_aliases, State#state.deref_aliases},
{attributes, ["dn"]}]) of
#eldap_search_result{entries = [_|_]} ->
DN;
_ ->
@ -421,6 +426,11 @@ parse_options(Host) ->
end,
eldap_utils:check_filter(DNFilter),
LocalFilter = ejabberd_config:get_local_option({ldap_local_filter, Host}),
DerefAliases = case ejabberd_config:get_local_option(
{ldap_deref_aliases, Host}) of
undefined -> never;
Val -> Val
end,
#state{host = Host,
eldap_id = Eldap_ID,
bind_eldap_id = Bind_Eldap_ID,
@ -438,6 +448,7 @@ parse_options(Host) ->
ufilter = UserFilter,
sfilter = SearchFilter,
lfilter = LocalFilter,
deref_aliases = DerefAliases,
dn_filter = DNFilter,
dn_filter_attrs = DNFilterAttrs
}.

View File

@ -269,8 +269,8 @@ try_call_command(Args, Auth, AccessCommands) ->
try call_command(Args, Auth, AccessCommands) of
{error, command_unknown} ->
{io_lib:format("Error: command ~p not known.", [hd(Args)]), ?STATUS_ERROR};
{error, wrong_number_parameters} ->
{"Error: wrong number of parameters", ?STATUS_ERROR};
{error, wrong_command_arguments} ->
{"Error: wrong arguments", ?STATUS_ERROR};
Res ->
Res
catch
@ -637,7 +637,7 @@ print_usage_help(MaxC, ShCode) ->
ArgsDef = [],
C = #ejabberd_commands{
desc = "Show help of ejabberd commands",
longdesc = LongDesc,
longdesc = lists:flatten(LongDesc),
args = ArgsDef,
result = {help, string}},
print_usage_command("help", C, MaxC, ShCode).

View File

@ -195,7 +195,7 @@ process_element(El,State) ->
add_user(El, Domain) ->
User = exmpp_xml:get_attribute(El, <<"name">>, none),
PasswordFormat = exmpp_xml:get_attribute(El, <<"password-format">>, none),
PasswordFormat = exmpp_xml:get_attribute(El, <<"password-format">>, <<"plaintext">>),
Password = exmpp_xml:get_attribute(El, <<"password">>, none),
add_user(El, Domain, User, PasswordFormat, Password).

View File

@ -1082,33 +1082,29 @@ get_addr_port(Server) ->
{ok, HEnt} ->
?DEBUG("srv lookup of '~s': ~p~n",
[Server, HEnt#hostent.h_addr_list]),
case HEnt#hostent.h_addr_list of
[] ->
[{Server, outgoing_s2s_port()}];
AddrList ->
%% Probabilities are not exactly proportional to weights
%% for simplicity (higher weigths are overvalued)
{A1, A2, A3} = now(),
random:seed(A1, A2, A3),
case (catch lists:map(
fun({Priority, Weight, Port, Host}) ->
N = case Weight of
0 -> 0;
_ -> (Weight + 1) * random:uniform()
end,
{Priority * 65536 - N, Host, Port}
end, AddrList)) of
{'EXIT', _Reason} ->
[{Server, outgoing_s2s_port()}];
SortedList ->
List = lists:map(
fun({_, Host, Port}) ->
{Host, Port}
end, lists:keysort(1, SortedList)),
?DEBUG("srv lookup of '~s': ~p~n", [Server, List]),
List
end
end
AddrList = HEnt#hostent.h_addr_list,
%% Probabilities are not exactly proportional to weights
%% for simplicity (higher weigths are overvalued)
{A1, A2, A3} = now(),
random:seed(A1, A2, A3),
case (catch lists:map(
fun({Priority, Weight, Port, Host}) ->
N = case Weight of
0 -> 0;
_ -> (Weight + 1) * random:uniform()
end,
{Priority * 65536 - N, Host, Port}
end, AddrList)) of
SortedList = [_|_] ->
List = lists:map(
fun({_, Host, Port}) ->
{Host, Port}
end, lists:keysort(1, SortedList)),
?DEBUG("srv lookup of '~s': ~p~n", [Server, List]),
List;
_ ->
[{Server, outgoing_s2s_port()}]
end
end.
srv_lookup(Server) ->

View File

@ -63,7 +63,7 @@ init([]) ->
ok -> ok;
{error, already_loaded} -> ok
end,
Port = open_port({spawn, ejabberd_zlib_drv}, [binary]),
Port = open_port({spawn, "ejabberd_zlib_drv"}, [binary]),
{ok, Port}.
@ -99,7 +99,7 @@ enable_zlib(SockMod, Socket) ->
ok -> ok;
{error, already_loaded} -> ok
end,
Port = open_port({spawn, ejabberd_zlib_drv}, [binary]),
Port = open_port({spawn, "ejabberd_zlib_drv"}, [binary]),
{ok, #zlibsock{sockmod = SockMod, socket = Socket, zlibport = Port}}.
disable_zlib(#zlibsock{sockmod = SockMod, socket = Socket, zlibport = Port}) ->

View File

@ -324,21 +324,13 @@ ctlexec ()
{
CONN_NAME=$1; shift
COMMAND=$@
CTLEXEC="$ERL \
$EXEC_CMD "$ERL \
$NAME ${CONN_NAME} \
-noinput \
-hidden \
-pa $EJABBERD_EBIN_PATH \
$KERNEL_OPTS \
-s ejabberd_ctl -extra $ERLANG_NODE"
# quote input from the command line
for i in $COMMAND; do
CTLEXEC="$CTLEXEC '$i'";
done
$EXEC_CMD "$CTLEXEC"
-s ejabberd_ctl -extra $ERLANG_NODE $COMMAND"
}
# display ctl usage

View File

@ -112,7 +112,7 @@
host = null, % Connected Host LDAP server
port = 389, % The LDAP server port
sockmod, % SockMod (gen_tcp|tls)
tls = none, % LDAP/LDAPS (none|starttls|tls)
tls = none, % LDAP/LDAPS (none|tls)
tls_options = [],
fd = null, % Socket filedescriptor.
rootdn = "", % Name of the entry to bind as
@ -323,6 +323,14 @@ parse_search_args([{timeout, Timeout}|T],A) when is_integer(Timeout) ->
parse_search_args(T,A#eldap_search{timeout = Timeout});
parse_search_args([{limit, Limit}|T],A) when is_integer(Limit) ->
parse_search_args(T,A#eldap_search{limit = Limit});
parse_search_args([{deref_aliases, never}|T],A) ->
parse_search_args(T,A#eldap_search{deref_aliases = neverDerefAliases});
parse_search_args([{deref_aliases, searching}|T],A) ->
parse_search_args(T,A#eldap_search{deref_aliases = derefInSearching});
parse_search_args([{deref_aliases, finding}|T],A) ->
parse_search_args(T,A#eldap_search{deref_aliases = derefFindingBaseObj});
parse_search_args([{deref_aliases, always}|T],A) ->
parse_search_args(T,A#eldap_search{deref_aliases = derefAlways});
parse_search_args([H|_],_) ->
throw({error,{unknown_arg, H}});
parse_search_args([],A) ->
@ -424,8 +432,8 @@ get_handle(Name) when is_list(Name) -> list_to_atom("eldap_" ++ Name).
%%----------------------------------------------------------------------
init([]) ->
case get_config() of
{ok, Hosts, Rootdn, Passwd, Opts} ->
init({Hosts, Rootdn, Passwd, Opts});
{ok, Hosts, Port, Rootdn, Passwd, Opts} ->
init({Hosts, Port, Rootdn, Passwd, Opts});
{error, Reason} ->
{stop, Reason}
end;
@ -441,8 +449,6 @@ init({Hosts, Port, Rootdn, Passwd, Opts}) ->
case Encrypt of
tls ->
?LDAPS_PORT;
starttls ->
?LDAP_PORT;
_ ->
?LDAP_PORT
end;
@ -702,7 +708,7 @@ gen_req({search, A}) ->
{searchRequest,
#'SearchRequest'{baseObject = A#eldap_search.base,
scope = v_scope(A#eldap_search.scope),
derefAliases = neverDerefAliases,
derefAliases = A#eldap_search.deref_aliases,
sizeLimit = A#eldap_search.limit,
timeLimit = v_timeout(A#eldap_search.timeout),
typesOnly = v_bool(A#eldap_search.types_only),
@ -902,14 +908,9 @@ cancel_timer(Timer) ->
%%% Sanity check of received packet
check_tag(Data) ->
case asn1rt_ber_bin:decode_tag(Data) of
{_Tag, Data1, _Rb} ->
case asn1rt_ber_bin:decode_length(Data1) of
{{_Len,_Data2}, _Rb2} -> ok;
_ -> throw({error,decoded_tag_length})
end;
_ -> throw({error,decoded_tag})
end.
{_Tag, Data1, _Rb} = asn1rt_ber_bin:decode_tag(Data),
{{_Len,_Data2}, _Rb2} = asn1rt_ber_bin:decode_length(Data1),
ok.
close_and_retry(S, Timeout) ->
catch (S#eldap.sockmod):close(S#eldap.fd),

View File

@ -28,6 +28,7 @@
limit = 0,
attributes = [],
types_only = false,
deref_aliases = neverDerefAliases,
timeout = 0}).

View File

@ -473,17 +473,18 @@ announce_commands(From, To,
-define(VVALUE(Val),
{xmlelement, "value", [], [{xmlcdata, Val}]}).
-define(VVALUEL(Val),
case Val of
"" -> [];
_ -> [?VVALUE(Val)]
end).
-define(TVFIELD(Type, Var, Val),
{xmlelement, "field", [{"type", Type},
{"var", Var}],
?VVALUEL(Val)}).
vvaluel(Val)}).
-define(HFIELD(), ?TVFIELD("hidden", "FORM_TYPE", ?NS_ADMIN)).
vvaluel(Val) ->
case Val of
"" -> [];
_ -> [?VVALUE(Val)]
end.
generate_adhoc_form(Lang, Node, ServerHost) ->
LNode = tokenize(Node),
{OldSubject, OldBody} = if (LNode == ?NS_ADMINL("edit-motd"))
@ -512,12 +513,12 @@ generate_adhoc_form(Lang, Node, ServerHost) ->
[{"var", "subject"},
{"type", "text-single"},
{"label", translate:translate(Lang, "Subject")}],
?VVALUEL(OldSubject)},
vvaluel(OldSubject)},
{xmlelement, "field",
[{"var", "body"},
{"type", "text-multi"},
{"label", translate:translate(Lang, "Message body")}],
?VVALUEL(OldBody)}]
vvaluel(OldBody)}]
end}.
join_lines([]) ->

View File

@ -1403,9 +1403,7 @@ set_form(_From, Host, ["running nodes", ENode, "modules", "start"], _Lang, XData
end;
_ ->
{error, ?ERR_BAD_REQUEST}
end;
_ ->
{error, ?ERR_BAD_REQUEST}
end
end
end;

View File

@ -31,7 +31,7 @@
-behaviour(gen_mod).
%% API
-export([start_link/2, start/2, stop/1]).
-export([start_link/2, start/2, stop/1, do_client_version/3]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,

View File

@ -52,7 +52,7 @@ init([]) ->
ok -> ok;
{error, already_loaded} -> ok
end,
Port = open_port({spawn, iconv_erl}, []),
Port = open_port({spawn, "iconv_erl"}, []),
ets:new(iconv_table, [set, public, named_table]),
ets:insert(iconv_table, {port, Port}),
{ok, Port}.

View File

@ -813,13 +813,9 @@ process_channel_topic_who(StateData, Chan, String) ->
Words = string:tokens(String, " "),
Msg1 = case Words of
[_, "333", _, _Chan, Whoset , Timeset] ->
case string:to_integer(Timeset) of
{Unixtimeset, _Rest} ->
"Topic for #" ++ Chan ++ " set by " ++ Whoset ++
" at " ++ unixtime2string(Unixtimeset);
_->
"Topic for #" ++ Chan ++ " set by " ++ Whoset
end;
{Unixtimeset, _Rest} = string:to_integer(Timeset),
"Topic for #" ++ Chan ++ " set by " ++ Whoset ++
" at " ++ unixtime2string(Unixtimeset);
[_, "333", _, _Chan, Whoset | _] ->
"Topic for #" ++ Chan ++ " set by " ++ Whoset;
_ ->
@ -1327,15 +1323,12 @@ filter_mirc_colors(Msg) ->
unixtime2string(Unixtime) ->
Secs = Unixtime + calendar:datetime_to_gregorian_seconds(
{{1970, 1, 1}, {0,0,0}}),
case calendar:universal_time_to_local_time(
calendar:gregorian_seconds_to_datetime(Secs)) of
{{Year, Month, Day}, {Hour, Minute, Second}} ->
lists:flatten(
io_lib:format("~4..0w-~2..0w-~2..0w ~2..0w:~2..0w:~2..0w",
[Year, Month, Day, Hour, Minute, Second]));
_->
"0000-00-00 00:00:00"
end.
{{Year, Month, Day}, {Hour, Minute, Second}} =
calendar:universal_time_to_local_time(
calendar:gregorian_seconds_to_datetime(Secs)),
lists:flatten(
io_lib:format("~4..0w-~2..0w-~2..0w ~2..0w:~2..0w:~2..0w",
[Year, Month, Day, Hour, Minute, Second])).
toupper([C | Cs]) ->
if

View File

@ -863,6 +863,7 @@ roomconfig_to_string(Options, Lang, FileFormat) ->
max_users -> "<div class=\"rcot\">" ++ OptText ++ ": \"" ++ htmlize(integer_to_list(T), FileFormat) ++ "\"</div>";
title -> "<div class=\"rcot\">" ++ OptText ++ ": \"" ++ htmlize(T, FileFormat) ++ "\"</div>";
description -> "<div class=\"rcot\">" ++ OptText ++ ": \"" ++ htmlize(T, FileFormat) ++ "\"</div>";
allow_private_messages_from_visitors -> "<div class=\"rcot\">" ++ OptText ++ ": \"" ++ htmlize(?T(atom_to_list(T)), FileFormat) ++ "\"</div>";
_ -> "\"" ++ T ++ "\""
end
end,
@ -884,7 +885,7 @@ get_roomconfig_text(moderated) -> "Make room moderated";
get_roomconfig_text(members_by_default) -> "Default users as participants";
get_roomconfig_text(allow_change_subj) -> "Allow users to change the subject";
get_roomconfig_text(allow_private_messages) -> "Allow users to send private messages";
get_roomconfig_text(allow_private_messages_from_visitors) -> "Allow visitors to send private messages";
get_roomconfig_text(allow_private_messages_from_visitors) -> "Allow visitors to send private messages to";
get_roomconfig_text(allow_query_users) -> "Allow users to query other users";
get_roomconfig_text(allow_user_invites) -> "Allow users to send invites";
get_roomconfig_text(logging) -> "Enable logging";
@ -944,7 +945,7 @@ get_room_state(RoomName, MucService) ->
RoomPid = R#muc_online_room.pid,
get_room_state(RoomPid);
[] ->
room_not_found
#state{}
end.
get_room_state(RoomPid) ->

View File

@ -304,16 +304,107 @@ normal_state({route, From, "",
NSD#state.room,
make_opts(NSD));
_ ->
ok
end,
{next_state, normal_state, NSD};
_ ->
{next_state, normal_state,
StateData}
{next_state, normal_state, StateData}
end;
false ->
{next_state, normal_state, StateData}
end
end;
IsVoiceRequest ->
NewStateData =
case (StateData#state.config)#config.allow_voice_requests of
true ->
MinInterval = (StateData#state.config)
#config.voice_request_min_interval,
BareFrom = jlib:jid_remove_resource( jlib:jid_tolower(From)),
NowPriority = -now_to_usec(now()),
CleanPriority =
NowPriority + MinInterval*1000000,
Times = clean_treap(
StateData#state.last_voice_request_time,
CleanPriority),
case treap:lookup(BareFrom, Times) of
error ->
Times1 = treap:insert(
BareFrom,
NowPriority,
true, Times),
NSD = StateData#state{last_voice_request_time = Times1},
send_voice_request(From, NSD),
NSD;
{ok, _, _} ->
ErrText = "Please, wait for "
"a while before sending "
"new voice request",
Err = jlib:make_error_reply(
Packet,
?ERRT_NOT_ACCEPTABLE(
Lang, ErrText)),
ejabberd_router:route(
StateData#state.jid,
From, Err),
StateData#state{
last_voice_request_time =
Times}
end;
false ->
{next_state, normal_state, StateData}
end
ErrText = "Voice requests are "
"disabled in this conference",
Err = jlib:make_error_reply(
Packet,
?ERRT_FORBIDDEN(
Lang, ErrText)),
ejabberd_router:route(StateData#state.jid, From, Err),
StateData
end,
{next_state, normal_state, NewStateData};
IsVoiceApprovement ->
NewStateData =
case is_moderator(From, StateData) of
true ->
case extract_jid_from_voice_approvement(Els) of
error ->
ErrText = "Failed to extract "
"JID from your voice "
"request approvement",
Err = jlib:make_error_reply(
Packet,
?ERRT_BAD_REQUEST(
Lang, ErrText)),
ejabberd_router:route(
StateData#state.jid,
From, Err),
StateData;
{ok, TargetJid} ->
case is_visitor(
TargetJid, StateData) of
true ->
Reason = [],
NSD = set_role(
TargetJid,
participant,
StateData),
catch send_new_presence(
TargetJid,
Reason, NSD),
NSD;
_ ->
StateData
end
end;
_ ->
ErrText = "Only moderators can "
"approve voice requests",
Err = jlib:make_error_reply(
Packet,
?ERRT_NOT_ALLOWED(
Lang, ErrText)),
ejabberd_router:route(StateData#state.jid, From, Err),
StateData
end,
{next_state, normal_state, NewStateData};
true ->
{next_state, normal_state, StateData}
end;
_ ->
ErrText = "Improper message type",
@ -481,7 +572,29 @@ normal_state({route, From, ToNick,
jlib:jid_replace_resource(
StateData#state.jid,
ToNick),
From, Err)
From, Err);
ToJIDs ->
SrcIsVisitor = is_visitor(From, StateData),
DstIsModerator = is_moderator(hd(ToJIDs), StateData),
PmFromVisitors = (StateData#state.config)#config.allow_private_messages_from_visitors,
if SrcIsVisitor == false;
PmFromVisitors == anyone;
(PmFromVisitors == moderators) and (DstIsModerator) ->
{ok, #user{nick = FromNick}} =
?DICT:find(jlib:jid_tolower(From),
StateData#state.users),
FromNickJID = jlib:jid_replace_resource(StateData#state.jid, FromNick),
[ejabberd_router:route(FromNickJID, ToJID, Packet) || ToJID <- ToJIDs];
true ->
ErrText = "It is not allowed to send private messages",
Err = jlib:make_error_reply(
Packet, ?ERRT_FORBIDDEN(Lang, ErrText)),
ejabberd_router:route(
jlib:jid_replace_resource(
StateData#state.jid,
ToNick),
From, Err)
end
end
end;
{true, false} ->
@ -1250,19 +1363,9 @@ expulse_participant(Packet, From, StateData, Reason1) ->
set_affiliation(JID, Affiliation, StateData) ->
LJID = jlib:jid_remove_resource(jlib:jid_tolower(JID)),
Affiliations = case Affiliation of
none ->
?DICT:erase(LJID,
StateData#state.affiliations);
_ ->
?DICT:store(LJID,
Affiliation,
StateData#state.affiliations)
end,
StateData#state{affiliations = Affiliations}.
set_affiliation(JID, Affiliation, StateData, "").
set_affiliation_and_reason(JID, Affiliation, Reason, StateData) ->
set_affiliation(JID, Affiliation, StateData, Reason) ->
LJID = jlib:jid_remove_resource(jlib:jid_tolower(JID)),
Affiliations = case Affiliation of
none ->
@ -1582,7 +1685,7 @@ remove_online_user(JID, StateData, Reason) ->
?DICT:erase(Nick, StateData#state.nicks);
{ok, U} ->
?DICT:store(Nick, U -- [LJID], StateData#state.nicks);
false ->
error ->
StateData#state.nicks
end,
StateData#state{users = Users, nicks = Nicks}.
@ -1693,6 +1796,12 @@ get_priority_from_presence(PresencePacket) ->
end
end.
find_nick_by_jid(Jid, StateData) ->
[{_, #user{nick = Nick}}] = lists:filter(
fun({_, #user{jid = FJid}}) -> FJid == Jid end,
?DICT:to_list(StateData#state.users)),
Nick.
is_nick_change(JID, Nick, StateData) ->
LJID = jlib:jid_tolower(JID),
case Nick of
@ -1726,7 +1835,6 @@ add_new_user(From, Nick, {xmlelement, _, Attrs, Els} = Packet, StateData) ->
mod_muc, max_user_conferences, 10),
Collision = nick_collision(From, Nick, StateData),
case {(ServiceAffiliation == owner orelse
MaxUsers == none orelse
((Affiliation == admin orelse Affiliation == owner) andalso
NUsers < MaxAdminUsers) orelse
NUsers < MaxUsers) andalso
@ -2222,7 +2330,7 @@ change_nick(JID, Nick, StateData) ->
?DICT:store(OldNick, OldNickUsers -- [LJID],
StateData#state.nicks))
end,
NewStateData = StateData#state{users = Users, nicks = Nicks},
NewStateData = StateData#state{users = Users, nicks = Nicks},
send_nick_changing(JID, OldNick, NewStateData, SendOldUnavailable, SendNewAvailable),
add_to_log(nickchange, {OldNick, Nick}, StateData),
NewStateData.
@ -2540,18 +2648,18 @@ process_admin_items_set(UJID, Items, Lang, StateData) ->
{JID, affiliation, outcast, Reason} ->
catch send_kickban_presence(
JID, Reason, "301", outcast, SD),
set_affiliation_and_reason(
JID, outcast, Reason,
set_role(JID, none, SD));
set_affiliation(
JID, outcast,
set_role(JID, none, SD), Reason);
{JID, affiliation, A, Reason} when
(A == admin) or (A == owner) ->
SD1 = set_affiliation_and_reason(JID, A, Reason, SD),
SD1 = set_affiliation(JID, A, SD, Reason),
SD2 = set_role(JID, moderator, SD1),
send_update_presence(JID, Reason, SD2),
SD2;
{JID, affiliation, member, Reason} ->
SD1 = set_affiliation_and_reason(
JID, member, Reason, SD),
SD1 = set_affiliation(
JID, member, SD, Reason),
SD2 = set_role(JID, participant, SD1),
send_update_presence(JID, Reason, SD2),
SD2;
@ -2572,7 +2680,7 @@ process_admin_items_set(UJID, Items, Lang, StateData) ->
NSD ->
NSD
end
end, StateData, Res),
end, StateData, lists:flatten(Res)),
case (NSD#state.config)#config.persistent of
true ->
mod_muc:store_room(NSD#state.host, NSD#state.room,
@ -2604,12 +2712,12 @@ find_changed_items(UJID, UAffiliation, URole,
"Jabber ID ~s is invalid"), [S]),
{error, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)};
J ->
{value, J}
{value, [J]}
end;
_ ->
case xml:get_attr("nick", Attrs) of
{value, N} ->
case find_jid_by_nick(N, StateData) of
case find_jids_by_nick(N, StateData) of
false ->
ErrText =
io_lib:format(
@ -2626,7 +2734,7 @@ find_changed_items(UJID, UAffiliation, URole,
end
end,
case TJID of
{value, JID} ->
{value, [JID|_]=JIDs} ->
TAffiliation = get_affiliation(JID, StateData),
TRole = get_role(JID, StateData),
case xml:get_attr("role", Attrs) of
@ -2676,16 +2784,13 @@ find_changed_items(UJID, UAffiliation, URole,
Items, Lang, StateData,
Res);
true ->
Reason = xml:get_path_s(Item, [{elem, "reason"}, cdata]),
MoreRes = [{jlib:jid_remove_resource(Jidx), affiliation, SAffiliation, Reason} || Jidx <- JIDs],
find_changed_items(
UJID,
UAffiliation, URole,
Items, Lang, StateData,
[{jlib:jid_remove_resource(JID),
affiliation,
SAffiliation,
xml:get_path_s(
Item, [{elem, "reason"},
cdata])} | Res]);
[MoreRes | Res]);
false ->
{error, ?ERR_NOT_ALLOWED}
end
@ -2733,14 +2838,13 @@ find_changed_items(UJID, UAffiliation, URole,
Items, Lang, StateData,
Res);
true ->
Reason = xml:get_path_s(Item, [{elem, "reason"}, cdata]),
MoreRes = [{Jidx, role, SRole, Reason} || Jidx <- JIDs],
find_changed_items(
UJID,
UAffiliation, URole,
Items, Lang, StateData,
[{JID, role, SRole,
xml:get_path_s(
Item, [{elem, "reason"},
cdata])} | Res]);
[MoreRes | Res]);
_ ->
{error, ?ERR_NOT_ALLOWED}
end
@ -3291,7 +3395,13 @@ get_config(Lang, StateData, From) ->
Config#config.allow_visitor_status),
?BOOLXFIELD("Allow visitors to change nickname",
"muc#roomconfig_allowvisitornickchange",
Config#config.allow_visitor_nickchange)
Config#config.allow_visitor_nickchange),
?BOOLXFIELD("Allow visitors to send voice requests",
"muc#roomconfig_allowvoicerequests",
Config#config.allow_voice_requests),
?STRINGXFIELD("Minimum interval between voice requests (in seconds)",
"muc#roomconfig_voicerequestmininterval",
erlang:integer_to_list(Config#config.voice_request_min_interval))
] ++
case ejabberd_captcha:is_feature_available() of
true ->
@ -3434,12 +3544,16 @@ set_xoption([{"muc#roomconfig_roomsecret", [Val]} | Opts], Config) ->
?SET_STRING_XOPT(password, Val);
set_xoption([{"anonymous", [Val]} | Opts], Config) ->
?SET_BOOL_XOPT(anonymous, Val);
set_xoption([{"muc#roomconfig_allowvoicerequests", [Val]} | Opts], Config) ->
?SET_BOOL_XOPT(allow_voice_requests, Val);
set_xoption([{"muc#roomconfig_voicerequestmininterval", [Val]} | Opts], Config) ->
?SET_NAT_XOPT(voice_request_min_interval, Val);
set_xoption([{"muc#roomconfig_whois", [Val]} | Opts], Config) ->
case Val of
"moderators" ->
?SET_BOOL_XOPT(anonymous, "1");
?SET_BOOL_XOPT(anonymous, integer_to_list(1));
"anyone" ->
?SET_BOOL_XOPT(anonymous, "0");
?SET_BOOL_XOPT(anonymous, integer_to_list(0));
_ ->
{error, ?ERR_BAD_REQUEST}
end;
@ -3526,6 +3640,8 @@ set_opts([{Opt, Val} | Opts], StateData) ->
anonymous -> StateData#state{config = (StateData#state.config)#config{anonymous = 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)}};
allow_voice_requests -> StateData#state{config = (StateData#state.config)#config{allow_voice_requests = Val}};
voice_request_min_interval -> StateData#state{config = (StateData#state.config)#config{voice_request_min_interval = Val}};
max_users ->
ServiceMaxUsers = get_service_max_users(StateData),
MaxUsers = if
@ -3571,6 +3687,8 @@ make_opts(StateData) ->
?MAKE_CONFIG_OPT(anonymous),
?MAKE_CONFIG_OPT(logging),
?MAKE_CONFIG_OPT(max_users),
?MAKE_CONFIG_OPT(allow_voice_requests),
?MAKE_CONFIG_OPT(voice_request_min_interval),
{captcha_whitelist,
?SETS:to_list((StateData#state.config)#config.captcha_whitelist)},
{affiliations, ?DICT:to_list(StateData#state.affiliations)},
@ -3732,9 +3850,136 @@ get_mucroom_disco_items(StateData) ->
end,
?DICT:to_list(StateData#state.users)).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Voice request support
is_voice_request(Els) ->
lists:foldl(
fun({xmlelement, "x", Attrs, _} = El, false) ->
case xml:get_attr_s("xmlns", Attrs) of
?NS_XDATA ->
case jlib:parse_xdata_submit(El) of
[_|_] = Fields ->
case {lists:keysearch("FORM_TYPE", 1, Fields),
lists:keysearch("muc#role", 1, Fields)} of
{{value,
{_, ["http://jabber.org/protocol/muc#request"]}},
{value, {_, ["participant"]}}} ->
true;
_ ->
false
end;
_ ->
false
end;
_ ->
false
end;
(_, Acc) ->
Acc
end, false, Els).
prepare_request_form(Requester, Nick, Lang) ->
{xmlelement, "message", [{"type", "normal"}],
[{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "form"}],
[{xmlelement, "title", [],
[{xmlcdata, translate:translate(Lang, "Voice request")}]},
{xmlelement, "instructions", [],
[{xmlcdata,
translate:translate(
Lang, "Either approve or decline the voice request.")}]},
{xmlelement, "field", [{"var", "FORM_TYPE"}, {"type", "hidden"}],
[{xmlelement, "value", [],
[{xmlcdata, "http://jabber.org/protocol/muc#request"}]}]},
{xmlelement, "field", [{"var", "muc#role"}, {"type", "hidden"}],
[{xmlelement, "value", [], [{xmlcdata, "participant"}]}]},
?STRINGXFIELD("User JID", "muc#jid", jlib:jid_to_string(Requester)),
?STRINGXFIELD("Nickname", "muc#roomnick", Nick),
?BOOLXFIELD("Grant voice to this person?", "muc#request_allow",
list_to_atom("false"))
]}]}.
send_voice_request(From, StateData) ->
Moderators = search_role(moderator, StateData),
FromNick = find_nick_by_jid(From, StateData),
lists:foreach(
fun({_, User}) ->
ejabberd_router:route(
StateData#state.jid,
User#user.jid,
prepare_request_form(From, FromNick, ""))
end, Moderators).
is_voice_approvement(Els) ->
lists:foldl(
fun({xmlelement, "x", Attrs, _} = El, false) ->
case xml:get_attr_s("xmlns", Attrs) of
?NS_XDATA ->
case jlib:parse_xdata_submit(El) of
[_|_] = Fs ->
case {lists:keysearch("FORM_TYPE", 1, Fs),
lists:keysearch("muc#role", 1, Fs),
lists:keysearch("muc#request_allow", 1, Fs)} of
{{value,
{_, ["http://jabber.org/protocol/muc#request"]}},
{value, {_, ["participant"]}},
{value, {_, [Flag]}}}
when Flag == "true"; Flag == "1" ->
true;
_ ->
false
end;
_ ->
false
end;
_ ->
false
end;
(_, Acc) ->
Acc
end, false, Els).
extract_jid_from_voice_approvement(Els) ->
lists:foldl(
fun({xmlelement, "x", _, _} = El, error) ->
Fields = case jlib:parse_xdata_submit(El) of
invalid -> [];
Res -> Res
end,
lists:foldl(
fun({"muc#jid", [JIDStr]}, error) ->
case jlib:string_to_jid(JIDStr) of
error -> error;
J -> {ok, J}
end;
(_, Acc) ->
Acc
end, error, Fields);
(_, Acc) ->
Acc
end, error, Els).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Invitation support
is_invitation(Els) ->
lists:foldl(
fun({xmlelement, "x", Attrs, _} = El, false) ->
case xml:get_attr_s("xmlns", Attrs) of
?NS_MUC_USER ->
case xml:get_subtag(El, "invite") of
false ->
false;
_ ->
true
end;
_ ->
false
end;
(_, Acc) ->
Acc
end, false, Els).
check_invitation(From, Els, Lang, StateData) ->
FAffiliation = get_affiliation(From, StateData),
CanInvite = (StateData#state.config)#config.allow_user_invites

View File

@ -45,6 +45,8 @@
password_protected = false,
password = "",
anonymous = true,
allow_voice_requests = true,
voice_request_min_interval = 1800,
max_users = ?MAX_USERS_DEFAULT,
logging = false,
captcha_whitelist = ?SETS:empty()
@ -69,6 +71,7 @@
jid,
config = #config{},
users = ?DICT:new(),
last_voice_request_time = treap:empty(),
robots = ?DICT:new(),
nicks = ?DICT:new(),
affiliations = ?DICT:new(),

View File

@ -2113,8 +2113,11 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) ->
PluginPayload -> PluginPayload
end,
ejabberd_hooks:run(pubsub_publish_item, ServerHost, [ServerHost, Node, Publisher, service_jid(Host), ItemId, BrPayload]),
broadcast_publish_item(Host, Node, NodeId, Type, Options, ItemId, jlib:jid_tolower(Publisher), BrPayload, Removed),
set_cached_item(Host, NodeId, ItemId, Publisher, Payload),
set_cached_item(Host, NodeId, ItemId, Publisher, BrPayload),
case get_option(Options, deliver_notifications) of
true -> broadcast_publish_item(Host, Node, NodeId, Type, Options, ItemId, jlib:jid_tolower(Publisher), BrPayload, Removed);
false -> ok
end,
case Result of
default -> {result, Reply};
_ -> {result, Result}
@ -2145,8 +2148,10 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) ->
case lists:member("auto-create", features(Type)) of
true ->
case create_node(Host, ServerHost, Node, Publisher, Type) of
{result, _} ->
publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload);
{result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}],
[{xmlelement, "create", [{"node", NewNode}], []}]}]} ->
publish_item(Host, ServerHost, list_to_binary(NewNode),
Publisher, ItemId, Payload);
_ ->
{error, ?ERR_ITEM_NOT_FOUND}
end;

View File

@ -1880,8 +1880,11 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) ->
PluginPayload -> PluginPayload
end,
ejabberd_hooks:run(pubsub_publish_item, ServerHost, [ServerHost, Node, Publisher, service_jid(Host), ItemId, BrPayload]),
broadcast_publish_item(Host, Node, NodeId, Type, Options, ItemId, jlib:jid_tolower(Publisher), BrPayload, Removed),
set_cached_item(Host, NodeId, ItemId, Publisher, Payload),
set_cached_item(Host, NodeId, ItemId, Publisher, BrPayload),
case get_option(Options, deliver_notifications) of
true -> broadcast_publish_item(Host, Node, NodeId, Type, Options, ItemId, jlib:jid_tolower(Publisher), BrPayload, Removed);
false -> ok
end,
case Result of
default -> {result, Reply};
_ -> {result, Result}
@ -1912,8 +1915,10 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) ->
case lists:member("auto-create", features(Type)) of
true ->
case create_node(Host, ServerHost, Node, Publisher, Type) of
{result, _} ->
publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload);
{result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}],
[{xmlelement, "create", [{"node", NewNode}], []}]}]} ->
publish_item(Host, ServerHost, list_to_binary(NewNode),
Publisher, ItemId, Payload);
_ ->
{error, ?ERR_ITEM_NOT_FOUND}
end;

View File

@ -136,10 +136,7 @@ create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) ->
{result, Allowed}.
create_node(NodeId, Owner) ->
case node_hometree:create_node(NodeId, Owner) of
{result, _} -> {result, []};
Error -> Error
end.
node_hometree:create_node(NodeId, Owner).
delete_node(Removed) ->
case node_hometree:delete_node(Removed) of

View File

@ -215,7 +215,7 @@ get_entity_subscriptions(_Host, Owner) ->
{selected, ["host", "node", "type", "nodeid", "jid", "subscriptions"], RItems} ->
lists:map(fun({H, N, T, I, J, S}) ->
O = node_hometree_odbc:decode_jid(H),
Node = nodetree_odbc:raw_to_node(O, {N, "", T, I}),
Node = nodetree_tree_odbc:raw_to_node(O, {N, "", T, I}),
{Node, node_hometree_odbc:decode_subscriptions(S), node_hometree_odbc:decode_jid(J)}
end, RItems);
_ ->
@ -249,7 +249,7 @@ get_entity_subscriptions_for_send_last(_Host, Owner) ->
{selected, ["host", "node", "type", "nodeid", "jid", "subscriptions"], RItems} ->
lists:map(fun({H, N, T, I, J, S}) ->
O = node_hometree_odbc:decode_jid(H),
Node = nodetree_odbc:raw_to_node(O, {N, "", T, I}),
Node = nodetree_tree_odbc:raw_to_node(O, {N, "", T, I}),
{Node, node_hometree_odbc:decode_subscriptions(S), node_hometree_odbc:decode_jid(J)}
end, RItems);
_ ->

View File

@ -1,5 +1,5 @@
--- mod_pubsub.erl 2011-08-29 09:35:41.000000000 +0200
+++ mod_pubsub_odbc.erl 2011-09-26 16:35:05.000000000 +0200
--- mod_pubsub.erl 2011-09-30 13:59:23.000000000 +0200
+++ mod_pubsub_odbc.erl 2011-09-30 14:04:34.000000000 +0200
@@ -42,7 +42,7 @@
%%% 6.2.3.1, 6.2.3.5, and 6.3. For information on subscription leases see
%%% XEP-0060 section 12.18.
@ -580,7 +580,7 @@
{PresenceSubscription, RosterGroup} = get_presence_and_roster_permissions(Host, Subscriber, Owners, AccessModel, AllowedGroups),
if
not SubscribeFeature ->
@@ -2278,7 +2045,7 @@
@@ -2283,7 +2050,7 @@
%% <p>The permission are not checked in this function.</p>
%% @todo We probably need to check that the user doing the query has the right
%% to read the items.
@ -589,7 +589,7 @@
MaxItems =
if
SMaxItems == "" -> get_max_items_node(Host);
@@ -2292,12 +2059,13 @@
@@ -2297,12 +2064,13 @@
{error, Error} ->
{error, Error};
_ ->
@ -604,7 +604,7 @@
{PresenceSubscription, RosterGroup} = get_presence_and_roster_permissions(Host, From, Owners, AccessModel, AllowedGroups),
if
not RetreiveFeature ->
@@ -2310,11 +2078,11 @@
@@ -2315,11 +2083,11 @@
node_call(Type, get_items,
[NodeId, From,
AccessModel, PresenceSubscription, RosterGroup,
@ -618,7 +618,7 @@
SendItems = case ItemIDs of
[] ->
Items;
@@ -2327,7 +2095,8 @@
@@ -2332,7 +2100,8 @@
%% number of items sent to MaxItems:
{result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}],
[{xmlelement, "items", nodeAttr(Node),
@ -628,7 +628,7 @@
Error ->
Error
end
@@ -2349,10 +2118,15 @@
@@ -2354,10 +2123,15 @@
Error -> Error
end.
get_allowed_items_call(Host, NodeIdx, From, Type, Options, Owners) ->
@ -645,7 +645,7 @@
%% @spec (Host, Node, NodeId, Type, LJID, Number) -> any()
@@ -2365,27 +2139,27 @@
@@ -2370,27 +2144,27 @@
%% @doc <p>Resend the items of a node to the user.</p>
%% @todo use cache-last-item feature
send_items(Host, Node, NodeId, Type, {U,S,R} = LJID, last) ->
@ -689,7 +689,7 @@
end
end;
send_items(Host, Node, NodeId, Type, {U,S,R} = LJID, Number) ->
@@ -2526,7 +2300,8 @@
@@ -2531,7 +2305,8 @@
error ->
{error, ?ERR_BAD_REQUEST};
_ ->
@ -699,7 +699,7 @@
case lists:member(Owner, Owners) of
true ->
OwnerJID = jlib:make_jid(Owner),
@@ -2536,24 +2311,7 @@
@@ -2541,24 +2316,7 @@
end,
lists:foreach(
fun({JID, Affiliation}) ->
@ -725,7 +725,7 @@
end, FilteredEntities),
{result, []};
_ ->
@@ -2606,9 +2364,9 @@
@@ -2611,9 +2369,9 @@
end.
read_sub(Subscriber, Node, NodeID, SubID, Lang) ->
@ -737,7 +737,7 @@
OptionsEl = {xmlelement, "options", [{"jid", jlib:jid_to_string(Subscriber)},
{"subid", SubID}|nodeAttr(Node)],
[XdataEl]},
@@ -2640,7 +2398,7 @@
@@ -2645,7 +2403,7 @@
end.
set_options_helper(Configuration, JID, NodeID, SubID, Type) ->
@ -746,7 +746,7 @@
{result, GoodSubOpts} -> GoodSubOpts;
_ -> invalid
end,
@@ -2839,8 +2597,8 @@
@@ -2844,8 +2602,8 @@
{"subscription", subscription_to_string(Sub)} | nodeAttr(Node)], []}]}]},
ejabberd_router:route(service_jid(Host), jlib:make_jid(JID), Stanza)
end,
@ -757,7 +757,7 @@
true ->
Result = lists:foldl(fun({JID, Subscription, SubId}, Acc) ->
@@ -3203,7 +2961,7 @@
@@ -3208,7 +2966,7 @@
Collection = tree_call(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)]),
{result, [{Depth, [{N, sub_with_options(N)} || N <- Nodes]} || {Depth, Nodes} <- Collection]}
end,
@ -766,7 +766,7 @@
{result, CollSubs} -> subscribed_nodes_by_jid(NotifyType, CollSubs);
_ -> []
end.
@@ -3272,8 +3030,8 @@
@@ -3277,8 +3035,8 @@
[]
end.
sub_with_options(JID, NodeId, SubId) ->
@ -777,7 +777,7 @@
_ -> {JID, SubId, []}
end.
@@ -3349,6 +3107,30 @@
@@ -3354,6 +3112,30 @@
Result
end.
@ -808,7 +808,7 @@
%% @spec (Host, Options) -> MaxItems
%% Host = host()
%% Options = [Option]
@@ -3479,7 +3261,7 @@
@@ -3484,7 +3266,7 @@
end
end,
case transaction(Host, Node, Action, transaction) of
@ -817,7 +817,7 @@
NodeId = TNode#pubsub_node.id,
Type = TNode#pubsub_node.type,
Options = TNode#pubsub_node.options,
@@ -3745,7 +3527,13 @@
@@ -3750,7 +3532,13 @@
tree_action(Host, Function, Args) ->
?DEBUG("tree_action ~p ~p ~p",[Host,Function,Args]),
Fun = fun() -> tree_call(Host, Function, Args) end,
@ -832,7 +832,7 @@
%% @doc <p>node plugin call.</p>
node_call(Type, Function, Args) ->
@@ -3765,13 +3553,13 @@
@@ -3770,13 +3558,13 @@
node_action(Host, Type, Function, Args) ->
?DEBUG("node_action ~p ~p ~p ~p",[Host,Type,Function,Args]),
@ -848,7 +848,7 @@
case tree_call(Host, get_node, [Host, Node]) of
N when is_record(N, pubsub_node) ->
case Action(N) of
@@ -3783,13 +3571,19 @@
@@ -3788,13 +3576,19 @@
Error
end
end, Trans).
@ -872,7 +872,7 @@
{result, Result} -> {result, Result};
{error, Error} -> {error, Error};
{atomic, {result, Result}} -> {result, Result};
@@ -3797,6 +3591,15 @@
@@ -3802,6 +3596,15 @@
{aborted, Reason} ->
?ERROR_MSG("transaction return internal error: ~p~n", [{aborted, Reason}]),
{error, ?ERR_INTERNAL_SERVER_ERROR};
@ -888,7 +888,7 @@
{'EXIT', Reason} ->
?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]),
{error, ?ERR_INTERNAL_SERVER_ERROR};
@@ -3805,6 +3608,17 @@
@@ -3810,6 +3613,17 @@
{error, ?ERR_INTERNAL_SERVER_ERROR}
end.

View File

@ -30,6 +30,7 @@
-behaviour(gen_mod).
-export([start/2, stop/1,
item_to_xml/1,
webadmin_menu/3, webadmin_page/3,
get_user_roster/2,
get_subscription_lists/3,
@ -616,14 +617,15 @@ add_user_to_group(Host, US, Group) ->
case regexp:match(LUser, "^@.+@$") of
{match,_,_} ->
GroupOpts = mod_shared_roster:get_group_opts(Host, Group),
AllUsersOpt =
case LUser == "@all@" of
true -> [{all_users, true}];
false -> []
MoreGroupOpts =
case LUser of
"@all@" -> [{all_users, true}];
"@online@" -> [{online_users, true}];
_ -> []
end,
mod_shared_roster:set_group_opts(
Host, Group,
GroupOpts ++ AllUsersOpt);
GroupOpts ++ MoreGroupOpts);
nomatch ->
%% Push this new user to members of groups where this group is displayed
push_user_to_displayed(LUser, LServer, Group, both),
@ -651,7 +653,9 @@ remove_user_from_group(Host, US, Group) ->
NewGroupOpts =
case LUser of
"@all@" ->
lists:filter(fun(X) -> X/={all_users,true} end, GroupOpts)
lists:filter(fun(X) -> X/={all_users,true} end, GroupOpts);
"@online@" ->
lists:filter(fun(X) -> X/={online_users,true} end, GroupOpts)
end,
mod_shared_roster:set_group_opts(Host, Group, NewGroupOpts);
nomatch ->
@ -726,8 +730,6 @@ displayed_to_groups(GroupName, LServer) ->
lists:member(GroupName, proplists:get_value(displayed_groups, Opts, []))
end, GroupsOpts).
push_item(_User, _Server, _From, none) ->
ok;
push_item(User, Server, From, Item) ->
%% It was
%% ejabberd_sm:route(jlib:make_jid("", "", ""),

View File

@ -63,6 +63,7 @@
base,
password,
uid,
deref_aliases,
group_attr,
group_desc,
user_desc,
@ -314,6 +315,7 @@ eldap_search(State, FilterParseArgs, AttributesList) ->
[{base, State#state.base},
{filter, EldapFilter},
{timeout, ?LDAP_SEARCH_TIMEOUT},
{deref_aliases, State#state.deref_aliases},
{attributes, AttributesList}]) of
#eldap_search_result{entries = Es} ->
%% A result with entries. Return their list.
@ -659,6 +661,15 @@ parse_options(Host, Opts) ->
"" -> GroupSubFilter;
_ -> "(&" ++ GroupSubFilter ++ ConfigFilter ++ ")"
end,
DerefAliases = case gen_mod:get_opt(deref_aliases, Opts, undefined) of
undefined ->
case ejabberd_config:get_local_option(
{deref_aliases, Host}) of
undefined -> never;
D -> D
end;
D -> D
end,
#state{host = Host,
eldap_id = Eldap_ID,
servers = LDAPServers,
@ -672,6 +683,7 @@ parse_options(Host, Opts) ->
base = LDAPBase,
password = Password,
uid = UIDAttr,
deref_aliases = DerefAliases,
group_attr = GroupAttr,
group_desc = GroupDesc,
user_desc = UserDesc,

View File

@ -167,12 +167,7 @@ get_local_stat(_Server, [], Name) when Name == "users/all-hosts/total" ->
ejabberd_auth:get_vh_registered_users_number(Host)
+ Total
end, 0, ejabberd_config:get_global_option(hosts)),
case NumUsers of
{'EXIT', _Reason} ->
?STATERR("500", "Internal Server Error");
Users ->
?STATVAL(integer_to_list(Users), "users")
end;
?STATVAL(integer_to_list(NumUsers), "users");
get_local_stat(_Server, _, Name) ->
?STATERR("404", "Not Found").

View File

@ -74,6 +74,7 @@
search_fields,
search_reported,
search_reported_attrs,
deref_aliases,
matches
}).
@ -287,9 +288,11 @@ find_ldap_user(User, State) ->
VCardAttrs = State#state.vcard_map_attrs,
case eldap_filter:parse(RFC2254_Filter, [{"%u", User}]) of
{ok, EldapFilter} ->
case eldap_pool:search(Eldap_ID, [{base, Base},
{filter, EldapFilter},
{attributes, VCardAttrs}]) of
case eldap_pool:search(Eldap_ID,
[{base, Base},
{filter, EldapFilter},
{deref_aliases, State#state.deref_aliases},
{attributes, VCardAttrs}]) of
#eldap_search_result{entries = [E | _]} ->
E;
_ ->
@ -572,10 +575,12 @@ search(State, Data) ->
Limit = State#state.matches,
ReportedAttrs = State#state.search_reported_attrs,
Filter = eldap:'and'([SearchFilter, eldap_utils:make_filter(Data, UIDs)]),
case eldap_pool:search(Eldap_ID, [{base, Base},
{filter, Filter},
{limit, Limit},
{attributes, ReportedAttrs}]) of
case eldap_pool:search(Eldap_ID,
[{base, Base},
{filter, Filter},
{limit, Limit},
{deref_aliases, State#state.deref_aliases},
{attributes, ReportedAttrs}]) of
#eldap_search_result{entries = E} ->
search_items(E, State);
_ ->
@ -779,6 +784,15 @@ parse_options(Host, Opts) ->
_ -> []
end
end, SearchReported) ++ UIDAttrs),
DerefAliases = case gen_mod:get_opt(deref_aliases, Opts, undefined) of
undefined ->
case ejabberd_config:get_local_option(
{deref_aliases, Host}) of
undefined -> never;
D -> D
end;
D -> D
end,
#state{serverhost = Host,
myhost = MyHost,
eldap_id = Eldap_ID,
@ -801,5 +815,6 @@ parse_options(Host, Opts) ->
search_fields = SearchFields,
search_reported = SearchReported,
search_reported_attrs = SearchReportedAttrs,
deref_aliases = DerefAliases,
matches = Matches
}.

View File

@ -458,7 +458,7 @@ decode_msg(Msg,Parent, Name, StateName, StateData, Mod, Time, Debug,
handle_msg(Msg, Parent, Name, StateName, StateData,
Mod, Time, Limits, Queue, QueueLen);
_Msg ->
Debug1 = sys:handle_debug(Debug, {?MODULE, print_event},
Debug1 = sys:handle_debug(Debug, fun print_event/3,
{Name, StateName}, {in, Msg}),
handle_msg(Msg, Parent, Name, StateName, StateData,
Mod, Time, Debug1, Limits, Queue, QueueLen)
@ -472,6 +472,8 @@ system_continue(Parent, Debug, [Name, StateName, StateData,
loop(Parent, Name, StateName, StateData, Mod, Time, Debug,
Limits, Queue, QueueLen).
-spec system_terminate(term(), _, _, [term(),...]) -> no_return().
system_terminate(Reason, _Parent, Debug,
[Name, StateName, StateData, Mod, _Time,
_Limits, Queue, _QueueLen]) ->
@ -603,12 +605,12 @@ handle_msg(Msg, Parent, Name, StateName, StateData,
From = from(Msg),
case catch dispatch(Msg, Mod, StateName, StateData) of
{next_state, NStateName, NStateData} ->
Debug1 = sys:handle_debug(Debug, {?MODULE, print_event},
Debug1 = sys:handle_debug(Debug, fun print_event/3,
{Name, NStateName}, return),
loop(Parent, Name, NStateName, NStateData,
Mod, infinity, Debug1, Limits, Queue, QueueLen);
{next_state, NStateName, NStateData, Time1} ->
Debug1 = sys:handle_debug(Debug, {?MODULE, print_event},
Debug1 = sys:handle_debug(Debug, fun print_event/3,
{Name, NStateName}, return),
loop(Parent, Name, NStateName, NStateData,
Mod, Time1, Debug1, Limits, Queue, QueueLen);
@ -689,7 +691,7 @@ reply({To, Tag}, Reply) ->
reply(Name, {To, Tag}, Reply, Debug, StateName) ->
reply({To, Tag}, Reply),
sys:handle_debug(Debug, {?MODULE, print_event}, Name,
sys:handle_debug(Debug, fun print_event/3, Name,
{out, Reply, To, StateName}).
%%% ---------------------------------------------------

View File

@ -37,8 +37,9 @@
client_key/2
]).
%% ejabberd doesn't implement SASLPREP, so we use the similar RESOURCEPREP instead
salted_password(Password, Salt, IterationCount) ->
hi(jlib:nameprep(Password), Salt, IterationCount).
hi(jlib:resourceprep(Password), Salt, IterationCount).
client_key(SaltedPassword) ->
crypto:sha_mac(SaltedPassword, "Client Key").
@ -53,29 +54,29 @@ client_signature(StoredKey, AuthMessage) ->
crypto:sha_mac(StoredKey, AuthMessage).
client_key(ClientProof, ClientSignature) ->
binary:list_to_bin(lists:zipwith(fun(X, Y) ->
list_to_binary(lists:zipwith(fun(X, Y) ->
X bxor Y
end,
binary:bin_to_list(ClientProof),
binary:bin_to_list(ClientSignature))).
binary_to_list(ClientProof),
binary_to_list(ClientSignature))).
server_signature(ServerKey, AuthMessage) ->
crypto:sha_mac(ServerKey, AuthMessage).
hi(Password, Salt, IterationCount) ->
U1 = crypto:sha_mac(Password, string:concat(binary:bin_to_list(Salt), [0,0,0,1])),
binary:list_to_bin(lists:zipwith(fun(X, Y) ->
U1 = crypto:sha_mac(Password, string:concat(binary_to_list(Salt), [0,0,0,1])),
list_to_binary(lists:zipwith(fun(X, Y) ->
X bxor Y
end,
binary:bin_to_list(U1),
binary:bin_to_list(hi_round(Password, U1, IterationCount-1)))).
binary_to_list(U1),
binary_to_list(hi_round(Password, U1, IterationCount-1)))).
hi_round(Password, UPrev, 1) ->
crypto:sha_mac(Password, UPrev);
hi_round(Password, UPrev, IterationCount) ->
U = crypto:sha_mac(Password, UPrev),
binary:list_to_bin(lists:zipwith(fun(X, Y) ->
list_to_binary(lists:zipwith(fun(X, Y) ->
X bxor Y
end,
binary:bin_to_list(U),
binary:bin_to_list(hi_round(Password, U, IterationCount-1)))).
binary_to_list(U),
binary_to_list(hi_round(Password, U, IterationCount-1)))).

View File

@ -47,7 +47,7 @@ start() ->
end,
case Res of
ok ->
Port = open_port({spawn, ?DRIVER}, [binary]),
Port = open_port({spawn, atom_to_list(?DRIVER)}, [binary]),
register(?DRIVER, Port);
{error, Reason} ->
?CRITICAL_MSG("unable to load driver '~s': ~s",

View File

@ -60,7 +60,7 @@ init([]) ->
ok -> ok;
{error, already_loaded} -> ok
end,
Port = open_port({spawn, stringprep_drv}, []),
Port = open_port({spawn, "stringprep_drv"}, []),
register(?STRINGPREP_PORT, Port),
{ok, Port}.

View File

@ -84,7 +84,7 @@ init([]) ->
ok -> ok;
{error, already_loaded} -> ok
end,
Port = open_port({spawn, tls_drv}, [binary]),
Port = open_port({spawn, "tls_drv"}, [binary]),
Res = port_control(Port, ?SET_CERTIFICATE_FILE_ACCEPT, "./ssl.pem" ++ [0]),
case Res of
<<0>> ->
@ -130,7 +130,7 @@ tcp_to_tls(TCPSocket, Options) ->
ok -> ok;
{error, already_loaded} -> ok
end,
Port = open_port({spawn, tls_drv}, [binary]),
Port = open_port({spawn, "tls_drv"}, [binary]),
Flags =
case lists:member(verify_none, Options) of
true ->
@ -267,7 +267,7 @@ test() ->
ok -> ok;
{error, already_loaded} -> ok
end,
Port = open_port({spawn, tls_drv}, [binary]),
Port = open_port({spawn, "tls_drv"}, [binary]),
?PRINT("open_port: ~p~n", [Port]),
PCRes = port_control(Port, ?SET_CERTIFICATE_FILE_ACCEPT,
"./ssl.pem" ++ [0]),

View File

@ -409,20 +409,12 @@ static int tls_drv_control(ErlDrvData handle,
break;
case GET_ENCRYPTED_OUTPUT:
die_unless(d->ssl, "SSL not initialized");
rlen = 1;
b = driver_alloc_binary(rlen + BUF_SIZE);
size = BIO_ctrl_pending(d->bio_write) + 1;
b = driver_alloc_binary(size);
b->orig_bytes[0] = 0;
while ((res = BIO_read(d->bio_write,
b->orig_bytes + rlen, BUF_SIZE)) > 0)
{
//printf("%d bytes of encrypted data read from state machine\r\n", res);
rlen += res;
b = driver_realloc_binary(b, rlen + BUF_SIZE);
}
b = driver_realloc_binary(b, rlen);
BIO_read(d->bio_write, b->orig_bytes + 1, size - 1);
*rbuf = (char *)b;
return rlen;
return size;
case GET_DECRYPTED_INPUT:
if (!SSL_is_init_finished(d->ssl))
{

View File

@ -63,8 +63,6 @@ insert1({HashKey1, Priority1, Value1, Left, Right} = Tree,
insert1(delete_root(Tree), HashKey, Priority, Value)
end.
heapify(nil) ->
nil;
heapify({_HashKey, _Priority, _Value, nil, nil} = Tree) ->
Tree;
heapify({HashKey, Priority, Value,

View File

@ -409,7 +409,7 @@ process_request(#state{request_method = Method,
when Method=:='GET' orelse Method=:='HEAD' orelse Method=:='DELETE' orelse Method=:='OPTIONS' ->
case (catch url_decode_q_split(Path)) of
{'EXIT', _} ->
process_request(false);
make_bad_request(State);
{NPath, Query} ->
LPath = [path_decode(NPE) || NPE <- string:tokens(NPath, "/")],
LQuery = case (catch parse_urlencoded(Query)) of
@ -507,7 +507,7 @@ process_request(#state{request_method = Method,
?DEBUG("client data: ~p~n", [Data]),
case (catch url_decode_q_split(Path)) of
{'EXIT', _} ->
process_request(false);
make_bad_request(State);
{NPath, _Query} ->
LPath = [path_decode(NPE) || NPE <- string:tokens(NPath, "/")],
LQuery = case (catch parse_urlencoded(Data)) of
@ -543,6 +543,9 @@ process_request(#state{request_method = Method,
end;
process_request(State) ->
make_bad_request(State).
make_bad_request(State) ->
make_xhtml_output(State,
400,
[],
@ -589,7 +592,7 @@ recv_data(State, Len, Acc) ->
end,
case (State#state.sockmod):recv(State#state.socket, Len2, 300000) of
{ok, Data} ->
recv_data(State, Len - size(Data), [Acc | Data]);
recv_data(State, Len - size(Data), [Acc | [Data]]);
_ ->
""
end;
@ -1179,8 +1182,8 @@ is_space(_) ->
strip_spaces(String) ->
strip_spaces(String, both).
strip_spaces(String, left) ->
drop_spaces(String);
%% strip_spaces(String, left) ->
%% drop_spaces(String);
strip_spaces(String, right) ->
lists:reverse(drop_spaces(lists:reverse(String)));
strip_spaces(String, both) ->

View File

@ -106,16 +106,6 @@ get_menu_items(global, cluster, Lang, JID) ->
);
get_menu_items(Host, cluster, Lang, JID) ->
{Base, _, Items} = make_host_menu(Host, [], Lang, JID),
lists:map(
fun({URI, Name}) ->
{Base++URI++"/", Name};
({URI, Name, _SubMenu}) ->
{Base++URI++"/", Name}
end,
Items
);
get_menu_items(Host, Node, Lang, JID) ->
{Base, _, Items} = make_host_node_menu(Host, Node, Lang, JID),
lists:map(
fun({URI, Name}) ->
{Base++URI++"/", Name};
@ -124,6 +114,16 @@ get_menu_items(Host, Node, Lang, JID) ->
end,
Items
).
%% get_menu_items(Host, Node, Lang, JID) ->
%% {Base, _, Items} = make_host_node_menu(Host, Node, Lang, JID),
%% lists:map(
%% fun({URI, Name}) ->
%% {Base++URI++"/", Name};
%% ({URI, Name, _SubMenu}) ->
%% {Base++URI++"/", Name}
%% end,
%% Items
%% ).
is_allowed_path(BasePath, {Path, _}, JID) ->
is_allowed_path(BasePath ++ [Path], JID);
@ -2023,7 +2023,6 @@ get_node(global, Node, ["db"], Query, Lang) ->
get_node(global, Node, ["backup"], Query, Lang) ->
HomeDirRaw = case {os:getenv("HOME"), os:type()} of
{EnvHome, _} when is_list(EnvHome) -> EnvHome;
{false, win32} -> "C:/";
{false, {win32, _Osname}} -> "C:/";
{false, _} -> "/tmp/"
end,

View File

@ -61,9 +61,10 @@
{".html", "text/html"},
{".jar", "application/java-archive"},
{".jpeg", "image/jpeg"},
{".jpg", "image/jpeg"},
{".jpg", "image/jpeg"},
{".js", "text/javascript"},
{".png", "image/png"},
{".svg", "image/svg+xml"},
{".txt", "text/plain"},
{".xml", "application/xml"},
{".xpi", "application/x-xpinstall"},

View File

@ -104,7 +104,7 @@ new(CallbackPid) ->
new(CallbackPid, infinity).
new(CallbackPid, MaxSize) ->
Port = open_port({spawn, expat_erl}, [binary]),
Port = open_port({spawn, "expat_erl"}, [binary]),
#xml_stream_state{callback_pid = CallbackPid,
port = Port,
stack = [],
@ -147,7 +147,7 @@ close(#xml_stream_state{port = Port}) ->
parse_element(Str) ->
Port = open_port({spawn, expat_erl}, [binary]),
Port = open_port({spawn, "expat_erl"}, [binary]),
Res = port_control(Port, ?PARSE_FINAL_COMMAND, Str),
port_close(Port),
process_element_events(binary_to_term(Res)).