mirror of
https://github.com/processone/ejabberd.git
synced 2024-07-06 23:22:36 +02:00
fix merge conflicts from 2.1.9
This commit is contained in:
commit
adf56dedf3
|
@ -2,7 +2,7 @@
|
||||||
"http://www.w3.org/TR/REC-html40/loose.dtd">
|
"http://www.w3.org/TR/REC-html40/loose.dtd">
|
||||||
<HTML>
|
<HTML>
|
||||||
<HEAD>
|
<HEAD>
|
||||||
<TITLE>Ejabberd 2.1.7 Developers Guide
|
<TITLE>Ejabberd 2.1.9 Developers Guide
|
||||||
</TITLE>
|
</TITLE>
|
||||||
|
|
||||||
<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
|
<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 -->
|
<!--HEVEA command line is: /usr/bin/hevea -fix -pedantic dev.tex -->
|
||||||
<!--CUT DEF section 1 --><P><A NAME="titlepage"></A>
|
<!--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="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>
|
<A HREF="xmpp:aleksey@jabber.ru"><TT>xmpp:aleksey@jabber.ru</TT></A></H3></TD></TR>
|
||||||
</TABLE><DIV CLASS="center">
|
</TABLE><DIV CLASS="center">
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"http://www.w3.org/TR/REC-html40/loose.dtd">
|
"http://www.w3.org/TR/REC-html40/loose.dtd">
|
||||||
<HTML>
|
<HTML>
|
||||||
<HEAD>
|
<HEAD>
|
||||||
<TITLE>Ejabberd 2.1.7 Feature Sheet
|
<TITLE>Ejabberd 2.1.9 Feature Sheet
|
||||||
</TITLE>
|
</TITLE>
|
||||||
|
|
||||||
<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
|
<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 -->
|
<!--HEVEA command line is: /usr/bin/hevea -fix -pedantic features.tex -->
|
||||||
<!--CUT DEF section 1 --><P><A NAME="titlepage"></A>
|
<!--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="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>
|
<A HREF="xmpp:sander@devrieze.dyndns.org"><TT>xmpp:sander@devrieze.dyndns.org</TT></A></H3></TD></TR>
|
||||||
</TABLE><DIV CLASS="center">
|
</TABLE><DIV CLASS="center">
|
||||||
|
|
100
doc/guide.html
100
doc/guide.html
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ejabberd 2.1.7
|
ejabberd 2.1.9
|
||||||
|
|
||||||
Installation and Operation Guide
|
Installation and Operation Guide
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ BLOCKQUOTE.figure DIV.center DIV.center HR{display:none;}
|
||||||
<HR SIZE=2><BR>
|
<HR SIZE=2><BR>
|
||||||
<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> </TD></TR>
|
<TR><TD ALIGN=right NOWRAP> </TD></TR>
|
||||||
<TR><TD ALIGN=right NOWRAP> <FONT SIZE=6>Installation and Operation Guide</FONT></TD></TR>
|
<TR><TD ALIGN=right NOWRAP> <FONT SIZE=6>Installation and Operation Guide</FONT></TD></TR>
|
||||||
</TABLE><BR>
|
</TABLE><BR>
|
||||||
|
@ -306,8 +306,9 @@ Note that the Windows service is a feature still in development,
|
||||||
and for example it doesn’t read the file ejabberdctl.cfg.</P><P>On a *nix system, if you want ejabberd to be started as daemon at boot time,
|
and for example it doesn’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 ’bin’ directory to something like <TT>/etc/init.d/ejabberd</TT>
|
copy <TT>ejabberd.init</TT> from the ’bin’ directory to something like <TT>/etc/init.d/ejabberd</TT>
|
||||||
(depending on your distribution).
|
(depending on your distribution).
|
||||||
Create a system user called <TT>ejabberd</TT>;
|
Create a system user called <TT>ejabberd</TT>,
|
||||||
it will be used by the script to start the server.
|
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’t start correctly in Windows,
|
Then you can call <TT>/etc/inid.d/ejabberd start</TT> as root to start the server.</P><P>If <TT>ejabberd</TT> doesn’t start correctly in Windows,
|
||||||
try to start it using the shortcut in desktop or start menu.
|
try to start it using the shortcut in desktop or start menu.
|
||||||
If the window shows error 14001, the solution is to install:
|
If the window shows error 14001, the solution is to install:
|
||||||
|
@ -525,8 +526,8 @@ Using <TT>ejabberdctl</TT> (see section <A HREF="#ejabberdctl">4.1</A>):
|
||||||
</PRE></LI><LI CLASS="li-enumerate">Using a XMPP client and In-Band Registration (see section <A HREF="#modregister">3.3.19</A>).
|
</PRE></LI><LI CLASS="li-enumerate">Using a XMPP client and In-Band Registration (see section <A HREF="#modregister">3.3.19</A>).
|
||||||
</LI></OL>
|
</LI></OL>
|
||||||
</LI><LI CLASS="li-enumerate">Edit the <TT>ejabberd</TT> configuration file to give administration rights to the XMPP account you created:
|
</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"}}.
|
<PRE CLASS="verbatim">{acl, admin, {user, "admin1", "example.org"}}.
|
||||||
{access, configure, [{allow, admins}]}.
|
{access, configure, [{allow, admin}]}.
|
||||||
</PRE>You can grant administrative privileges to many XMPP accounts,
|
</PRE>You can grant administrative privileges to many XMPP accounts,
|
||||||
and also to accounts in other XMPP servers.
|
and also to accounts in other XMPP servers.
|
||||||
</LI><LI CLASS="li-enumerate">Restart <TT>ejabberd</TT> to load the new configuration.
|
</LI><LI CLASS="li-enumerate">Restart <TT>ejabberd</TT> to load the new configuration.
|
||||||
|
@ -1051,17 +1052,40 @@ internal (default) — See section <A HREF="#internalauth">3.1.4</A>.
|
||||||
<A HREF="#mssql">3.2.2</A> and <A HREF="#odbc">3.2.4</A>.
|
<A HREF="#mssql">3.2.2</A> and <A HREF="#odbc">3.2.4</A>.
|
||||||
</LI><LI CLASS="li-itemize">anonymous — See section <A HREF="#saslanonymous">3.1.4</A>.
|
</LI><LI CLASS="li-itemize">anonymous — See section <A HREF="#saslanonymous">3.1.4</A>.
|
||||||
</LI><LI CLASS="li-itemize">pam — See section <A HREF="#pam">3.1.4</A>.
|
</LI><LI CLASS="li-itemize">pam — See section <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>
|
<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.
|
</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">
|
</P><UL CLASS="itemize"><LI CLASS="li-itemize">
|
||||||
To use internal authentication on <TT>example.org</TT> and LDAP
|
To use internal authentication on <TT>example.org</TT> and LDAP
|
||||||
authentication on <TT>example.net</TT>:
|
authentication on <TT>example.net</TT>:
|
||||||
<PRE CLASS="verbatim">{host_config, "example.org", [{auth_method, [internal]}]}.
|
<PRE CLASS="verbatim">{host_config, "example.org", [{auth_method, [internal]}]}.
|
||||||
{host_config, "example.net", [{auth_method, [ldap]}]}.
|
{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}.
|
<PRE CLASS="verbatim">{auth_method, internal}.
|
||||||
|
{auth_password_format, scram}.
|
||||||
</PRE></LI></UL><P> <A NAME="extauth"></A> </P><!--TOC subsubsection External Script-->
|
</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>
|
<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,
|
</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
|
</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:
|
matches <TT>Regexp</TT> on local virtual hosts. Example:
|
||||||
<PRE CLASS="verbatim">{acl, tests, {user_regexp, "^test[0-9]*$"}}.
|
<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:
|
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
|
</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:
|
matches <TT>Regexp</TT>. Example:
|
||||||
<PRE CLASS="verbatim">{acl, icq, {server_regexp, "^icq\\."}}.
|
<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’t proceed if a certificate is invalid.
|
When <TT>hard</TT> is enabled <TT>ejabberd</TT> doesn’t proceed if a certificate is invalid.
|
||||||
When <TT>soft</TT> is enabled <TT>ejabberd</TT> proceeds even if check fails.
|
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.
|
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.
|
</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 389 if encryption is disabled; and 636 if encryption is enabled.
|
The default port is 389 if encryption is disabled; and 636 if encryption is enabled.
|
||||||
If you configure a value, it is stored in <TT>ejabberd</TT>’s database.
|
If you configure a value, it is stored in <TT>ejabberd</TT>’s database.
|
||||||
|
@ -1710,6 +1744,7 @@ the value previously stored in the database will be used instead of the default
|
||||||
is <TT>""</TT> which means ‘anonymous connection’.
|
is <TT>""</TT> which means ‘anonymous connection’.
|
||||||
</DD><DT CLASS="dt-description"><B><TT>{ldap_password, Password}</TT></B></DT><DD CLASS="dd-description"> Bind password. The default
|
</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>.
|
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:
|
</DD></DL><P>Example:
|
||||||
</P><PRE CLASS="verbatim">{auth_method, ldap}.
|
</P><PRE CLASS="verbatim">{auth_method, ldap}.
|
||||||
{ldap_servers, ["ldap.example.org"]}.
|
{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> </TD></TR>
|
<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> </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="#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> </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> </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> </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> </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> </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> </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="#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> </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> </TD></TR>
|
||||||
|
@ -2077,7 +2112,7 @@ able to send such messages).
|
||||||
</DD></DL><P>Examples:
|
</DD></DL><P>Examples:
|
||||||
</P><UL CLASS="itemize"><LI CLASS="li-itemize">
|
</P><UL CLASS="itemize"><LI CLASS="li-itemize">
|
||||||
Only administrators can send announcements:
|
Only administrators can send announcements:
|
||||||
<PRE CLASS="verbatim">{access, announce, [{allow, admins}]}.
|
<PRE CLASS="verbatim">{access, announce, [{allow, admin}]}.
|
||||||
|
|
||||||
{modules,
|
{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></LI><LI CLASS="li-itemize">Administrators as well as the direction can send announcements:
|
||||||
<PRE CLASS="verbatim">{acl, direction, {user, "big_boss", "example.org"}}.
|
<PRE CLASS="verbatim">{acl, direction, {user, "big_boss", "example.org"}}.
|
||||||
{acl, direction, {user, "assistant", "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}]}.
|
{allow, direction}]}.
|
||||||
|
|
||||||
{modules,
|
{modules,
|
||||||
|
@ -2497,6 +2532,7 @@ The available room options and the default values are:
|
||||||
<DL CLASS="description"><DT CLASS="dt-description">
|
<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.
|
<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, 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_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_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
|
</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
|
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
|
be stored in /var/www/muclogs, and the local time will be used. Finally, the
|
||||||
top link will be the default <CODE><a href="/">Home</a></CODE>.
|
top link will be the default <CODE><a href="/">Home</a></CODE>.
|
||||||
<PRE CLASS="verbatim">{acl, admins, {user, "admin1", "example.org"}}.
|
<PRE CLASS="verbatim">{acl, admin, {user, "admin1", "example.org"}}.
|
||||||
{acl, admins, {user, "admin2", "example.net"}}.
|
{acl, admin, {user, "admin2", "example.net"}}.
|
||||||
|
|
||||||
{access, muc_log, [{allow, admins},
|
{access, muc_log, [{allow, admin},
|
||||||
{deny, all}]}.
|
{deny, all}]}.
|
||||||
|
|
||||||
{modules,
|
{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
|
<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.
|
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:
|
</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, [
|
{5281, ejabberd_http, [
|
||||||
tls,
|
tls,
|
||||||
|
@ -3131,7 +3169,8 @@ list of JIDs which will be notified each time a new account is registered.
|
||||||
{mod_register_web, []},
|
{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,
|
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>-->
|
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>  <A HREF="#modroster"><TT>mod_roster</TT></A></H3><!--SEC END --><P> <A NAME="modroster"></A>
|
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc59">3.3.21</A>  <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
|
its own optional parameters. The first group of parameters has the same
|
||||||
meaning as the top-level LDAP parameters to set the authentication method:
|
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_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_password</TT>, <TT>ldap_base</TT>, <TT>ldap_uids</TT>,
|
||||||
<TT>ldap_filter</TT>. See section <A HREF="#ldapauth">3.2.5</A> for detailed information
|
<TT>ldap_deref_aliases</TT> and <TT>ldap_filter</TT>.
|
||||||
|
See section <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
|
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
|
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">
|
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>.
|
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">
|
</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.
|
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">
|
</DD><DT CLASS="dt-description"><B><TT>ERL_INETRC</TT></B></DT><DD CLASS="dd-description">
|
||||||
Indicates which IP name resolution to use.
|
Indicates which IP name resolution to use.
|
||||||
If using <TT>-sname</TT>, specify either this option or <TT>-kernel inetrc filepath</TT>.
|
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>).
|
connections (see section <A HREF="#epmd">5.2</A>).
|
||||||
</DD><DT CLASS="dt-description"><B><TT>-detached</TT></B></DT><DD CLASS="dd-description">
|
</DD><DT CLASS="dt-description"><B><TT>-detached</TT></B></DT><DD CLASS="dd-description">
|
||||||
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 background processes.
|
||||||
</DD><DT CLASS="dt-description"><B><TT>-noinput</TT></B></DT><DD CLASS="dd-description">
|
</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.
|
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">
|
</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.
|
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">
|
</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 ‘<TT>admin@example.com</TT>’ on<BR>
|
||||||
<CODE>http://example.org:5280/admin/server/example.com/</CODE> you can only
|
<CODE>http://example.org:5280/admin/server/example.com/</CODE> you can only
|
||||||
administer the virtual host <TT>example.com</TT>.
|
administer the virtual host <TT>example.com</TT>.
|
||||||
The account ‘<TT>reviewer@example.com</TT>’ can browse that vhost in read-only mode.
|
The account ‘<TT>reviewer@example.com</TT>’ can browse that vhost in read-only mode.
|
||||||
<PRE CLASS="verbatim">{acl, admins, {user, "admin", "example.net"}}.
|
<PRE CLASS="verbatim">{acl, admin, {user, "admin", "example.net"}}.
|
||||||
{host_config, "example.com", [{acl, admins, {user, "admin", "example.com"}}]}.
|
{host_config, "example.com", [{acl, admin, {user, "admin", "example.com"}}]}.
|
||||||
{host_config, "example.com", [{acl, viewers, {user, "reviewer", "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}]}.
|
{access, webadmin_view, [{allow, viewers}]}.
|
||||||
|
|
||||||
{hosts, ["example.org"]}.
|
{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,
|
In order for this communication to work,
|
||||||
<TT>epmd</TT> must be running and listening for name requests in the port 4369.
|
<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
|
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.
|
each <TT>ejabberd</TT> instance is called an <TT>ejabberd</TT> node.
|
||||||
Those <TT>ejabberd</TT> nodes use a special Erlang communication method to
|
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.
|
build the cluster, and EPMD is again needed listening in the port 4369.
|
||||||
|
|
|
@ -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,
|
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}
|
copy \term{ejabberd.init} from the 'bin' directory to something like \term{/etc/init.d/ejabberd}
|
||||||
(depending on your distribution).
|
(depending on your distribution).
|
||||||
Create a system user called \term{ejabberd};
|
Create a system user called \term{ejabberd},
|
||||||
it will be used by the script to start the server.
|
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.
|
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,
|
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]*$"}}.
|
{acl, tests, {user_regexp, "^test[0-9]*$"}}.
|
||||||
\end{verbatim}
|
\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:
|
that matches \term{Regexp} at server \term{Server}. Example:
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
{acl, tests, {user_Userregexp, "^test", "example.org"}}.
|
{acl, tests, {user_regexp, "^test", "example.org"}}.
|
||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
\titem{\{server\_regexp, Regexp\}} Matches any JID from the server that
|
\titem{\{server\_regexp, Regexp\}} Matches any JID from the server that
|
||||||
matches \term{Regexp}. Example:
|
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'.
|
is~\term{""} which means `anonymous connection'.
|
||||||
\titem{\{ldap\_password, Password\}} \ind{options!ldap\_password}Bind password. The default
|
\titem{\{ldap\_password, Password\}} \ind{options!ldap\_password}Bind password. The default
|
||||||
value is \term{""}.
|
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}
|
\end{description}
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
@ -4697,8 +4699,9 @@ The \modvcardldap{} module has
|
||||||
its own optional parameters. The first group of parameters has the same
|
its own optional parameters. The first group of parameters has the same
|
||||||
meaning as the top-level LDAP parameters to set the authentication method:
|
meaning as the top-level LDAP parameters to set the authentication method:
|
||||||
\option{ldap\_servers}, \option{ldap\_port}, \option{ldap\_rootdn},
|
\option{ldap\_servers}, \option{ldap\_port}, \option{ldap\_rootdn},
|
||||||
\option{ldap\_password}, \option{ldap\_base}, \option{ldap\_uids}, and
|
\option{ldap\_password}, \option{ldap\_base}, \option{ldap\_uids},
|
||||||
\option{ldap\_filter}. See section~\ref{ldapauth} for detailed information
|
\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
|
about these options. If one of these options is not set, \ejabberd{} will look
|
||||||
for the top-level option with the same name.
|
for the top-level option with the same name.
|
||||||
|
|
||||||
|
|
56
doc/release_notes_2.1.9.txt
Normal file
56
doc/release_notes_2.1.9.txt
Normal 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/
|
|
@ -1,2 +1,2 @@
|
||||||
% ejabberd version (automatically generated).
|
% ejabberd version (automatically generated).
|
||||||
\newcommand{\version}{2.1.7}
|
\newcommand{\version}{2.1.9}
|
||||||
|
|
|
@ -55,6 +55,8 @@ mech_step(#state{step = 2} = State, ClientIn) ->
|
||||||
case string:tokens(ClientIn, ",") of
|
case string:tokens(ClientIn, ",") of
|
||||||
[CBind, UserNameAttribute, ClientNonceAttribute] when (CBind == "y") or (CBind == "n") ->
|
[CBind, UserNameAttribute, ClientNonceAttribute] when (CBind == "y") or (CBind == "n") ->
|
||||||
case parse_attribute(UserNameAttribute) of
|
case parse_attribute(UserNameAttribute) of
|
||||||
|
{error, Reason} ->
|
||||||
|
{error, Reason};
|
||||||
{_, EscapedUserName} ->
|
{_, EscapedUserName} ->
|
||||||
case unescape_username(EscapedUserName) of
|
case unescape_username(EscapedUserName) of
|
||||||
error ->
|
error ->
|
||||||
|
@ -89,11 +91,7 @@ mech_step(#state{step = 2} = State, ClientIn) ->
|
||||||
_Else ->
|
_Else ->
|
||||||
{error, "not-supported"}
|
{error, "not-supported"}
|
||||||
end
|
end
|
||||||
end;
|
end
|
||||||
{error, Reason} ->
|
|
||||||
{error, Reason};
|
|
||||||
_Else ->
|
|
||||||
{error, "bad-protocol"}
|
|
||||||
end;
|
end;
|
||||||
_Else ->
|
_Else ->
|
||||||
{error, "bad-protocol"}
|
{error, "bad-protocol"}
|
||||||
|
@ -139,18 +137,14 @@ mech_step(#state{step = 4} = State, ClientIn) ->
|
||||||
parse_attribute(Attribute) ->
|
parse_attribute(Attribute) ->
|
||||||
AttributeLen = string:len(Attribute),
|
AttributeLen = string:len(Attribute),
|
||||||
if
|
if
|
||||||
AttributeLen > 3 ->
|
AttributeLen >= 3 ->
|
||||||
SecondChar = lists:nth(2, Attribute),
|
SecondChar = lists:nth(2, Attribute),
|
||||||
case is_alpha(lists:nth(1, Attribute)) of
|
case is_alpha(lists:nth(1, Attribute)) of
|
||||||
true ->
|
true ->
|
||||||
if
|
if
|
||||||
SecondChar == $= ->
|
SecondChar == $= ->
|
||||||
case string:substr(Attribute, 3) of
|
String = string:substr(Attribute, 3),
|
||||||
String when is_list(String) ->
|
{lists:nth(1, Attribute), String};
|
||||||
{lists:nth(1, Attribute), String};
|
|
||||||
_Else ->
|
|
||||||
{error, "bad-format failed"}
|
|
||||||
end;
|
|
||||||
true ->
|
true ->
|
||||||
{error, "bad-format second char not equal sign"}
|
{error, "bad-format second char not equal sign"}
|
||||||
end;
|
end;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
{application, ejabberd,
|
{application, ejabberd,
|
||||||
[{description, "ejabberd"},
|
[{description, "ejabberd"},
|
||||||
{vsn, "2.2.x"},
|
{vsn, "2.2.9"},
|
||||||
{modules, [acl,
|
{modules, [acl,
|
||||||
adhoc,
|
adhoc,
|
||||||
configure,
|
configure,
|
||||||
|
|
|
@ -478,7 +478,7 @@ restore(Path) ->
|
||||||
%% Obsolete tables or tables created by module who are no longer used are not
|
%% Obsolete tables or tables created by module who are no longer used are not
|
||||||
%% restored and are ignored.
|
%% restored and are ignored.
|
||||||
keep_tables() ->
|
keep_tables() ->
|
||||||
lists:flatten([acl, passwd, config, local_config, disco_publish,
|
lists:flatten([acl, passwd, config, local_config,
|
||||||
keep_modules_tables()]).
|
keep_modules_tables()]).
|
||||||
|
|
||||||
%% Returns the list of modules tables in use, according to the list of actually
|
%% Returns the list of modules tables in use, according to the list of actually
|
||||||
|
|
|
@ -114,7 +114,7 @@ init() ->
|
||||||
ok -> ok;
|
ok -> ok;
|
||||||
{error, already_loaded} -> ok
|
{error, already_loaded} -> ok
|
||||||
end,
|
end,
|
||||||
Port = open_port({spawn, expat_erl}, [binary]),
|
Port = open_port({spawn, "expat_erl"}, [binary]),
|
||||||
loop(Port).
|
loop(Port).
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -306,19 +306,16 @@ is_user_exists_in_other_modules_loop([AuthModule|AuthModules], User, Server) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
%% @spec (User, Server) -> ok | error | {error, not_allowed}
|
%% @spec (User, Server) -> ok
|
||||||
%% @doc Remove user.
|
%% @doc Remove user.
|
||||||
%% Note: it may return ok even if there was some problem removing the user.
|
%% Note: it may return ok even if there was some problem removing the user.
|
||||||
remove_user(User, Server) ->
|
remove_user(User, Server) ->
|
||||||
R = lists:foreach(
|
lists:foreach(
|
||||||
fun(M) ->
|
fun(M) ->
|
||||||
M:remove_user(User, Server)
|
M:remove_user(User, Server)
|
||||||
end, auth_modules(Server)),
|
end, auth_modules(Server)),
|
||||||
case R of
|
ejabberd_hooks:run(remove_user, jlib:nameprep(Server), [User, Server]),
|
||||||
ok -> ejabberd_hooks:run(remove_user, jlib:nameprep(Server), [User, Server]);
|
ok.
|
||||||
_ -> none
|
|
||||||
end,
|
|
||||||
R.
|
|
||||||
|
|
||||||
%% @spec (User, Server, Password) -> ok | not_exists | not_allowed | bad_request | error
|
%% @spec (User, Server, Password) -> ok | not_exists | not_allowed | bad_request | error
|
||||||
%% @doc Try to remove user if the provided password is correct.
|
%% @doc Try to remove user if the provided password is correct.
|
||||||
|
|
|
@ -75,6 +75,7 @@
|
||||||
ufilter,
|
ufilter,
|
||||||
sfilter,
|
sfilter,
|
||||||
lfilter, %% Local filter (performed by ejabberd, not LDAP)
|
lfilter, %% Local filter (performed by ejabberd, not LDAP)
|
||||||
|
deref_aliases,
|
||||||
dn_filter,
|
dn_filter,
|
||||||
dn_filter_attrs
|
dn_filter_attrs
|
||||||
}).
|
}).
|
||||||
|
@ -230,10 +231,12 @@ get_vh_registered_users_ldap(Server) ->
|
||||||
ResAttrs = result_attrs(State),
|
ResAttrs = result_attrs(State),
|
||||||
case eldap_filter:parse(State#state.sfilter) of
|
case eldap_filter:parse(State#state.sfilter) of
|
||||||
{ok, EldapFilter} ->
|
{ok, EldapFilter} ->
|
||||||
case eldap_pool:search(Eldap_ID, [{base, State#state.base},
|
case eldap_pool:search(Eldap_ID,
|
||||||
{filter, EldapFilter},
|
[{base, State#state.base},
|
||||||
{timeout, ?LDAP_SEARCH_TIMEOUT},
|
{filter, EldapFilter},
|
||||||
{attributes, ResAttrs}]) of
|
{timeout, ?LDAP_SEARCH_TIMEOUT},
|
||||||
|
{deref_aliases, State#state.deref_aliases},
|
||||||
|
{attributes, ResAttrs}]) of
|
||||||
#eldap_search_result{entries = Entries} ->
|
#eldap_search_result{entries = Entries} ->
|
||||||
lists:flatmap(
|
lists:flatmap(
|
||||||
fun(#eldap_entry{attributes = Attrs,
|
fun(#eldap_entry{attributes = Attrs,
|
||||||
|
@ -285,6 +288,7 @@ find_user_dn(User, State) ->
|
||||||
case eldap_pool:search(State#state.eldap_id,
|
case eldap_pool:search(State#state.eldap_id,
|
||||||
[{base, State#state.base},
|
[{base, State#state.base},
|
||||||
{filter, Filter},
|
{filter, Filter},
|
||||||
|
{deref_aliases, State#state.deref_aliases},
|
||||||
{attributes, ResAttrs}]) of
|
{attributes, ResAttrs}]) of
|
||||||
#eldap_search_result{entries = [#eldap_entry{attributes = Attrs,
|
#eldap_search_result{entries = [#eldap_entry{attributes = Attrs,
|
||||||
object_name = DN} | _]} ->
|
object_name = DN} | _]} ->
|
||||||
|
@ -322,10 +326,11 @@ is_valid_dn(DN, Attrs, State) ->
|
||||||
end ++ [{"%d", State#state.host}, {"%D", DN}],
|
end ++ [{"%d", State#state.host}, {"%D", DN}],
|
||||||
case eldap_filter:parse(State#state.dn_filter, SubstValues) of
|
case eldap_filter:parse(State#state.dn_filter, SubstValues) of
|
||||||
{ok, EldapFilter} ->
|
{ok, EldapFilter} ->
|
||||||
case eldap_pool:search(State#state.eldap_id, [
|
case eldap_pool:search(State#state.eldap_id,
|
||||||
{base, State#state.base},
|
[{base, State#state.base},
|
||||||
{filter, EldapFilter},
|
{filter, EldapFilter},
|
||||||
{attributes, ["dn"]}]) of
|
{deref_aliases, State#state.deref_aliases},
|
||||||
|
{attributes, ["dn"]}]) of
|
||||||
#eldap_search_result{entries = [_|_]} ->
|
#eldap_search_result{entries = [_|_]} ->
|
||||||
DN;
|
DN;
|
||||||
_ ->
|
_ ->
|
||||||
|
@ -421,6 +426,11 @@ parse_options(Host) ->
|
||||||
end,
|
end,
|
||||||
eldap_utils:check_filter(DNFilter),
|
eldap_utils:check_filter(DNFilter),
|
||||||
LocalFilter = ejabberd_config:get_local_option({ldap_local_filter, Host}),
|
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,
|
#state{host = Host,
|
||||||
eldap_id = Eldap_ID,
|
eldap_id = Eldap_ID,
|
||||||
bind_eldap_id = Bind_Eldap_ID,
|
bind_eldap_id = Bind_Eldap_ID,
|
||||||
|
@ -438,6 +448,7 @@ parse_options(Host) ->
|
||||||
ufilter = UserFilter,
|
ufilter = UserFilter,
|
||||||
sfilter = SearchFilter,
|
sfilter = SearchFilter,
|
||||||
lfilter = LocalFilter,
|
lfilter = LocalFilter,
|
||||||
|
deref_aliases = DerefAliases,
|
||||||
dn_filter = DNFilter,
|
dn_filter = DNFilter,
|
||||||
dn_filter_attrs = DNFilterAttrs
|
dn_filter_attrs = DNFilterAttrs
|
||||||
}.
|
}.
|
||||||
|
|
|
@ -269,8 +269,8 @@ try_call_command(Args, Auth, AccessCommands) ->
|
||||||
try call_command(Args, Auth, AccessCommands) of
|
try call_command(Args, Auth, AccessCommands) of
|
||||||
{error, command_unknown} ->
|
{error, command_unknown} ->
|
||||||
{io_lib:format("Error: command ~p not known.", [hd(Args)]), ?STATUS_ERROR};
|
{io_lib:format("Error: command ~p not known.", [hd(Args)]), ?STATUS_ERROR};
|
||||||
{error, wrong_number_parameters} ->
|
{error, wrong_command_arguments} ->
|
||||||
{"Error: wrong number of parameters", ?STATUS_ERROR};
|
{"Error: wrong arguments", ?STATUS_ERROR};
|
||||||
Res ->
|
Res ->
|
||||||
Res
|
Res
|
||||||
catch
|
catch
|
||||||
|
@ -637,7 +637,7 @@ print_usage_help(MaxC, ShCode) ->
|
||||||
ArgsDef = [],
|
ArgsDef = [],
|
||||||
C = #ejabberd_commands{
|
C = #ejabberd_commands{
|
||||||
desc = "Show help of ejabberd commands",
|
desc = "Show help of ejabberd commands",
|
||||||
longdesc = LongDesc,
|
longdesc = lists:flatten(LongDesc),
|
||||||
args = ArgsDef,
|
args = ArgsDef,
|
||||||
result = {help, string}},
|
result = {help, string}},
|
||||||
print_usage_command("help", C, MaxC, ShCode).
|
print_usage_command("help", C, MaxC, ShCode).
|
||||||
|
|
|
@ -195,7 +195,7 @@ process_element(El,State) ->
|
||||||
|
|
||||||
add_user(El, Domain) ->
|
add_user(El, Domain) ->
|
||||||
User = exmpp_xml:get_attribute(El, <<"name">>, none),
|
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),
|
Password = exmpp_xml:get_attribute(El, <<"password">>, none),
|
||||||
add_user(El, Domain, User, PasswordFormat, Password).
|
add_user(El, Domain, User, PasswordFormat, Password).
|
||||||
|
|
||||||
|
|
|
@ -1082,33 +1082,29 @@ get_addr_port(Server) ->
|
||||||
{ok, HEnt} ->
|
{ok, HEnt} ->
|
||||||
?DEBUG("srv lookup of '~s': ~p~n",
|
?DEBUG("srv lookup of '~s': ~p~n",
|
||||||
[Server, HEnt#hostent.h_addr_list]),
|
[Server, HEnt#hostent.h_addr_list]),
|
||||||
case HEnt#hostent.h_addr_list of
|
AddrList = HEnt#hostent.h_addr_list,
|
||||||
[] ->
|
%% Probabilities are not exactly proportional to weights
|
||||||
[{Server, outgoing_s2s_port()}];
|
%% for simplicity (higher weigths are overvalued)
|
||||||
AddrList ->
|
{A1, A2, A3} = now(),
|
||||||
%% Probabilities are not exactly proportional to weights
|
random:seed(A1, A2, A3),
|
||||||
%% for simplicity (higher weigths are overvalued)
|
case (catch lists:map(
|
||||||
{A1, A2, A3} = now(),
|
fun({Priority, Weight, Port, Host}) ->
|
||||||
random:seed(A1, A2, A3),
|
N = case Weight of
|
||||||
case (catch lists:map(
|
0 -> 0;
|
||||||
fun({Priority, Weight, Port, Host}) ->
|
_ -> (Weight + 1) * random:uniform()
|
||||||
N = case Weight of
|
end,
|
||||||
0 -> 0;
|
{Priority * 65536 - N, Host, Port}
|
||||||
_ -> (Weight + 1) * random:uniform()
|
end, AddrList)) of
|
||||||
end,
|
SortedList = [_|_] ->
|
||||||
{Priority * 65536 - N, Host, Port}
|
List = lists:map(
|
||||||
end, AddrList)) of
|
fun({_, Host, Port}) ->
|
||||||
{'EXIT', _Reason} ->
|
{Host, Port}
|
||||||
[{Server, outgoing_s2s_port()}];
|
end, lists:keysort(1, SortedList)),
|
||||||
SortedList ->
|
?DEBUG("srv lookup of '~s': ~p~n", [Server, List]),
|
||||||
List = lists:map(
|
List;
|
||||||
fun({_, Host, Port}) ->
|
_ ->
|
||||||
{Host, Port}
|
[{Server, outgoing_s2s_port()}]
|
||||||
end, lists:keysort(1, SortedList)),
|
end
|
||||||
?DEBUG("srv lookup of '~s': ~p~n", [Server, List]),
|
|
||||||
List
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
srv_lookup(Server) ->
|
srv_lookup(Server) ->
|
||||||
|
|
|
@ -63,7 +63,7 @@ init([]) ->
|
||||||
ok -> ok;
|
ok -> ok;
|
||||||
{error, already_loaded} -> ok
|
{error, already_loaded} -> ok
|
||||||
end,
|
end,
|
||||||
Port = open_port({spawn, ejabberd_zlib_drv}, [binary]),
|
Port = open_port({spawn, "ejabberd_zlib_drv"}, [binary]),
|
||||||
{ok, Port}.
|
{ok, Port}.
|
||||||
|
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ enable_zlib(SockMod, Socket) ->
|
||||||
ok -> ok;
|
ok -> ok;
|
||||||
{error, already_loaded} -> ok
|
{error, already_loaded} -> ok
|
||||||
end,
|
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}}.
|
{ok, #zlibsock{sockmod = SockMod, socket = Socket, zlibport = Port}}.
|
||||||
|
|
||||||
disable_zlib(#zlibsock{sockmod = SockMod, socket = Socket, zlibport = Port}) ->
|
disable_zlib(#zlibsock{sockmod = SockMod, socket = Socket, zlibport = Port}) ->
|
||||||
|
|
|
@ -324,21 +324,13 @@ 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"
|
-s ejabberd_ctl -extra $ERLANG_NODE $COMMAND"
|
||||||
|
|
||||||
# quote input from the command line
|
|
||||||
for i in $COMMAND; do
|
|
||||||
CTLEXEC="$CTLEXEC '$i'";
|
|
||||||
done
|
|
||||||
|
|
||||||
$EXEC_CMD "$CTLEXEC"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# display ctl usage
|
# display ctl usage
|
||||||
|
|
|
@ -112,7 +112,7 @@
|
||||||
host = null, % Connected Host LDAP server
|
host = null, % Connected Host LDAP server
|
||||||
port = 389, % The LDAP server port
|
port = 389, % The LDAP server port
|
||||||
sockmod, % SockMod (gen_tcp|tls)
|
sockmod, % SockMod (gen_tcp|tls)
|
||||||
tls = none, % LDAP/LDAPS (none|starttls|tls)
|
tls = none, % LDAP/LDAPS (none|tls)
|
||||||
tls_options = [],
|
tls_options = [],
|
||||||
fd = null, % Socket filedescriptor.
|
fd = null, % Socket filedescriptor.
|
||||||
rootdn = "", % Name of the entry to bind as
|
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(T,A#eldap_search{timeout = Timeout});
|
||||||
parse_search_args([{limit, Limit}|T],A) when is_integer(Limit) ->
|
parse_search_args([{limit, Limit}|T],A) when is_integer(Limit) ->
|
||||||
parse_search_args(T,A#eldap_search{limit = 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|_],_) ->
|
parse_search_args([H|_],_) ->
|
||||||
throw({error,{unknown_arg, H}});
|
throw({error,{unknown_arg, H}});
|
||||||
parse_search_args([],A) ->
|
parse_search_args([],A) ->
|
||||||
|
@ -424,8 +432,8 @@ get_handle(Name) when is_list(Name) -> list_to_atom("eldap_" ++ Name).
|
||||||
%%----------------------------------------------------------------------
|
%%----------------------------------------------------------------------
|
||||||
init([]) ->
|
init([]) ->
|
||||||
case get_config() of
|
case get_config() of
|
||||||
{ok, Hosts, Rootdn, Passwd, Opts} ->
|
{ok, Hosts, Port, Rootdn, Passwd, Opts} ->
|
||||||
init({Hosts, Rootdn, Passwd, Opts});
|
init({Hosts, Port, Rootdn, Passwd, Opts});
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
{stop, Reason}
|
{stop, Reason}
|
||||||
end;
|
end;
|
||||||
|
@ -441,8 +449,6 @@ init({Hosts, Port, Rootdn, Passwd, Opts}) ->
|
||||||
case Encrypt of
|
case Encrypt of
|
||||||
tls ->
|
tls ->
|
||||||
?LDAPS_PORT;
|
?LDAPS_PORT;
|
||||||
starttls ->
|
|
||||||
?LDAP_PORT;
|
|
||||||
_ ->
|
_ ->
|
||||||
?LDAP_PORT
|
?LDAP_PORT
|
||||||
end;
|
end;
|
||||||
|
@ -702,7 +708,7 @@ gen_req({search, A}) ->
|
||||||
{searchRequest,
|
{searchRequest,
|
||||||
#'SearchRequest'{baseObject = A#eldap_search.base,
|
#'SearchRequest'{baseObject = A#eldap_search.base,
|
||||||
scope = v_scope(A#eldap_search.scope),
|
scope = v_scope(A#eldap_search.scope),
|
||||||
derefAliases = neverDerefAliases,
|
derefAliases = A#eldap_search.deref_aliases,
|
||||||
sizeLimit = A#eldap_search.limit,
|
sizeLimit = A#eldap_search.limit,
|
||||||
timeLimit = v_timeout(A#eldap_search.timeout),
|
timeLimit = v_timeout(A#eldap_search.timeout),
|
||||||
typesOnly = v_bool(A#eldap_search.types_only),
|
typesOnly = v_bool(A#eldap_search.types_only),
|
||||||
|
@ -902,14 +908,9 @@ cancel_timer(Timer) ->
|
||||||
|
|
||||||
%%% Sanity check of received packet
|
%%% Sanity check of received packet
|
||||||
check_tag(Data) ->
|
check_tag(Data) ->
|
||||||
case asn1rt_ber_bin:decode_tag(Data) of
|
{_Tag, Data1, _Rb} = asn1rt_ber_bin:decode_tag(Data),
|
||||||
{_Tag, Data1, _Rb} ->
|
{{_Len,_Data2}, _Rb2} = asn1rt_ber_bin:decode_length(Data1),
|
||||||
case asn1rt_ber_bin:decode_length(Data1) of
|
ok.
|
||||||
{{_Len,_Data2}, _Rb2} -> ok;
|
|
||||||
_ -> throw({error,decoded_tag_length})
|
|
||||||
end;
|
|
||||||
_ -> throw({error,decoded_tag})
|
|
||||||
end.
|
|
||||||
|
|
||||||
close_and_retry(S, Timeout) ->
|
close_and_retry(S, Timeout) ->
|
||||||
catch (S#eldap.sockmod):close(S#eldap.fd),
|
catch (S#eldap.sockmod):close(S#eldap.fd),
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
limit = 0,
|
limit = 0,
|
||||||
attributes = [],
|
attributes = [],
|
||||||
types_only = false,
|
types_only = false,
|
||||||
|
deref_aliases = neverDerefAliases,
|
||||||
timeout = 0}).
|
timeout = 0}).
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -473,17 +473,18 @@ announce_commands(From, To,
|
||||||
|
|
||||||
-define(VVALUE(Val),
|
-define(VVALUE(Val),
|
||||||
{xmlelement, "value", [], [{xmlcdata, Val}]}).
|
{xmlelement, "value", [], [{xmlcdata, Val}]}).
|
||||||
-define(VVALUEL(Val),
|
|
||||||
case Val of
|
|
||||||
"" -> [];
|
|
||||||
_ -> [?VVALUE(Val)]
|
|
||||||
end).
|
|
||||||
-define(TVFIELD(Type, Var, Val),
|
-define(TVFIELD(Type, Var, Val),
|
||||||
{xmlelement, "field", [{"type", Type},
|
{xmlelement, "field", [{"type", Type},
|
||||||
{"var", Var}],
|
{"var", Var}],
|
||||||
?VVALUEL(Val)}).
|
vvaluel(Val)}).
|
||||||
-define(HFIELD(), ?TVFIELD("hidden", "FORM_TYPE", ?NS_ADMIN)).
|
-define(HFIELD(), ?TVFIELD("hidden", "FORM_TYPE", ?NS_ADMIN)).
|
||||||
|
|
||||||
|
vvaluel(Val) ->
|
||||||
|
case Val of
|
||||||
|
"" -> [];
|
||||||
|
_ -> [?VVALUE(Val)]
|
||||||
|
end.
|
||||||
|
|
||||||
generate_adhoc_form(Lang, Node, ServerHost) ->
|
generate_adhoc_form(Lang, Node, ServerHost) ->
|
||||||
LNode = tokenize(Node),
|
LNode = tokenize(Node),
|
||||||
{OldSubject, OldBody} = if (LNode == ?NS_ADMINL("edit-motd"))
|
{OldSubject, OldBody} = if (LNode == ?NS_ADMINL("edit-motd"))
|
||||||
|
@ -512,12 +513,12 @@ generate_adhoc_form(Lang, Node, ServerHost) ->
|
||||||
[{"var", "subject"},
|
[{"var", "subject"},
|
||||||
{"type", "text-single"},
|
{"type", "text-single"},
|
||||||
{"label", translate:translate(Lang, "Subject")}],
|
{"label", translate:translate(Lang, "Subject")}],
|
||||||
?VVALUEL(OldSubject)},
|
vvaluel(OldSubject)},
|
||||||
{xmlelement, "field",
|
{xmlelement, "field",
|
||||||
[{"var", "body"},
|
[{"var", "body"},
|
||||||
{"type", "text-multi"},
|
{"type", "text-multi"},
|
||||||
{"label", translate:translate(Lang, "Message body")}],
|
{"label", translate:translate(Lang, "Message body")}],
|
||||||
?VVALUEL(OldBody)}]
|
vvaluel(OldBody)}]
|
||||||
end}.
|
end}.
|
||||||
|
|
||||||
join_lines([]) ->
|
join_lines([]) ->
|
||||||
|
|
|
@ -1403,9 +1403,7 @@ set_form(_From, Host, ["running nodes", ENode, "modules", "start"], _Lang, XData
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
{error, ?ERR_BAD_REQUEST}
|
{error, ?ERR_BAD_REQUEST}
|
||||||
end;
|
end
|
||||||
_ ->
|
|
||||||
{error, ?ERR_BAD_REQUEST}
|
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
-behaviour(gen_mod).
|
-behaviour(gen_mod).
|
||||||
|
|
||||||
%% API
|
%% API
|
||||||
-export([start_link/2, start/2, stop/1]).
|
-export([start_link/2, start/2, stop/1, do_client_version/3]).
|
||||||
|
|
||||||
%% 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,
|
||||||
|
|
|
@ -52,7 +52,7 @@ init([]) ->
|
||||||
ok -> ok;
|
ok -> ok;
|
||||||
{error, already_loaded} -> ok
|
{error, already_loaded} -> ok
|
||||||
end,
|
end,
|
||||||
Port = open_port({spawn, iconv_erl}, []),
|
Port = open_port({spawn, "iconv_erl"}, []),
|
||||||
ets:new(iconv_table, [set, public, named_table]),
|
ets:new(iconv_table, [set, public, named_table]),
|
||||||
ets:insert(iconv_table, {port, Port}),
|
ets:insert(iconv_table, {port, Port}),
|
||||||
{ok, Port}.
|
{ok, Port}.
|
||||||
|
|
|
@ -813,13 +813,9 @@ process_channel_topic_who(StateData, Chan, String) ->
|
||||||
Words = string:tokens(String, " "),
|
Words = string:tokens(String, " "),
|
||||||
Msg1 = case Words of
|
Msg1 = case Words of
|
||||||
[_, "333", _, _Chan, Whoset , Timeset] ->
|
[_, "333", _, _Chan, Whoset , Timeset] ->
|
||||||
case string:to_integer(Timeset) of
|
{Unixtimeset, _Rest} = string:to_integer(Timeset),
|
||||||
{Unixtimeset, _Rest} ->
|
"Topic for #" ++ Chan ++ " set by " ++ Whoset ++
|
||||||
"Topic for #" ++ Chan ++ " set by " ++ Whoset ++
|
" at " ++ unixtime2string(Unixtimeset);
|
||||||
" at " ++ unixtime2string(Unixtimeset);
|
|
||||||
_->
|
|
||||||
"Topic for #" ++ Chan ++ " set by " ++ Whoset
|
|
||||||
end;
|
|
||||||
[_, "333", _, _Chan, Whoset | _] ->
|
[_, "333", _, _Chan, Whoset | _] ->
|
||||||
"Topic for #" ++ Chan ++ " set by " ++ Whoset;
|
"Topic for #" ++ Chan ++ " set by " ++ Whoset;
|
||||||
_ ->
|
_ ->
|
||||||
|
@ -1327,15 +1323,12 @@ filter_mirc_colors(Msg) ->
|
||||||
unixtime2string(Unixtime) ->
|
unixtime2string(Unixtime) ->
|
||||||
Secs = Unixtime + calendar:datetime_to_gregorian_seconds(
|
Secs = Unixtime + calendar:datetime_to_gregorian_seconds(
|
||||||
{{1970, 1, 1}, {0,0,0}}),
|
{{1970, 1, 1}, {0,0,0}}),
|
||||||
case calendar:universal_time_to_local_time(
|
{{Year, Month, Day}, {Hour, Minute, Second}} =
|
||||||
calendar:gregorian_seconds_to_datetime(Secs)) of
|
calendar:universal_time_to_local_time(
|
||||||
{{Year, Month, Day}, {Hour, Minute, Second}} ->
|
calendar:gregorian_seconds_to_datetime(Secs)),
|
||||||
lists:flatten(
|
lists:flatten(
|
||||||
io_lib:format("~4..0w-~2..0w-~2..0w ~2..0w:~2..0w:~2..0w",
|
io_lib:format("~4..0w-~2..0w-~2..0w ~2..0w:~2..0w:~2..0w",
|
||||||
[Year, Month, Day, Hour, Minute, Second]));
|
[Year, Month, Day, Hour, Minute, Second])).
|
||||||
_->
|
|
||||||
"0000-00-00 00:00:00"
|
|
||||||
end.
|
|
||||||
|
|
||||||
toupper([C | Cs]) ->
|
toupper([C | Cs]) ->
|
||||||
if
|
if
|
||||||
|
|
|
@ -863,6 +863,7 @@ roomconfig_to_string(Options, Lang, FileFormat) ->
|
||||||
max_users -> "<div class=\"rcot\">" ++ OptText ++ ": \"" ++ htmlize(integer_to_list(T), FileFormat) ++ "\"</div>";
|
max_users -> "<div class=\"rcot\">" ++ OptText ++ ": \"" ++ htmlize(integer_to_list(T), FileFormat) ++ "\"</div>";
|
||||||
title -> "<div class=\"rcot\">" ++ OptText ++ ": \"" ++ htmlize(T, FileFormat) ++ "\"</div>";
|
title -> "<div class=\"rcot\">" ++ OptText ++ ": \"" ++ htmlize(T, FileFormat) ++ "\"</div>";
|
||||||
description -> "<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 ++ "\""
|
_ -> "\"" ++ T ++ "\""
|
||||||
end
|
end
|
||||||
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(members_by_default) -> "Default users as participants";
|
||||||
get_roomconfig_text(allow_change_subj) -> "Allow users to change the subject";
|
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) -> "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_query_users) -> "Allow users to query other users";
|
||||||
get_roomconfig_text(allow_user_invites) -> "Allow users to send invites";
|
get_roomconfig_text(allow_user_invites) -> "Allow users to send invites";
|
||||||
get_roomconfig_text(logging) -> "Enable logging";
|
get_roomconfig_text(logging) -> "Enable logging";
|
||||||
|
@ -944,7 +945,7 @@ get_room_state(RoomName, MucService) ->
|
||||||
RoomPid = R#muc_online_room.pid,
|
RoomPid = R#muc_online_room.pid,
|
||||||
get_room_state(RoomPid);
|
get_room_state(RoomPid);
|
||||||
[] ->
|
[] ->
|
||||||
room_not_found
|
#state{}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
get_room_state(RoomPid) ->
|
get_room_state(RoomPid) ->
|
||||||
|
|
|
@ -304,16 +304,107 @@ normal_state({route, From, "",
|
||||||
NSD#state.room,
|
NSD#state.room,
|
||||||
make_opts(NSD));
|
make_opts(NSD));
|
||||||
_ ->
|
_ ->
|
||||||
ok
|
{next_state, normal_state, StateData}
|
||||||
end,
|
end;
|
||||||
{next_state, normal_state, NSD};
|
false ->
|
||||||
_ ->
|
{next_state, normal_state, StateData}
|
||||||
{next_state, normal_state,
|
end
|
||||||
StateData}
|
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;
|
end;
|
||||||
false ->
|
false ->
|
||||||
{next_state, normal_state, StateData}
|
ErrText = "Voice requests are "
|
||||||
end
|
"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;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
ErrText = "Improper message type",
|
ErrText = "Improper message type",
|
||||||
|
@ -481,7 +572,29 @@ normal_state({route, From, ToNick,
|
||||||
jlib:jid_replace_resource(
|
jlib:jid_replace_resource(
|
||||||
StateData#state.jid,
|
StateData#state.jid,
|
||||||
ToNick),
|
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
|
||||||
end;
|
end;
|
||||||
{true, false} ->
|
{true, false} ->
|
||||||
|
@ -1250,19 +1363,9 @@ expulse_participant(Packet, From, StateData, Reason1) ->
|
||||||
|
|
||||||
|
|
||||||
set_affiliation(JID, Affiliation, StateData) ->
|
set_affiliation(JID, Affiliation, StateData) ->
|
||||||
LJID = jlib:jid_remove_resource(jlib:jid_tolower(JID)),
|
set_affiliation(JID, Affiliation, StateData, "").
|
||||||
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_and_reason(JID, Affiliation, Reason, StateData) ->
|
set_affiliation(JID, Affiliation, StateData, Reason) ->
|
||||||
LJID = jlib:jid_remove_resource(jlib:jid_tolower(JID)),
|
LJID = jlib:jid_remove_resource(jlib:jid_tolower(JID)),
|
||||||
Affiliations = case Affiliation of
|
Affiliations = case Affiliation of
|
||||||
none ->
|
none ->
|
||||||
|
@ -1582,7 +1685,7 @@ remove_online_user(JID, StateData, Reason) ->
|
||||||
?DICT:erase(Nick, StateData#state.nicks);
|
?DICT:erase(Nick, StateData#state.nicks);
|
||||||
{ok, U} ->
|
{ok, U} ->
|
||||||
?DICT:store(Nick, U -- [LJID], StateData#state.nicks);
|
?DICT:store(Nick, U -- [LJID], StateData#state.nicks);
|
||||||
false ->
|
error ->
|
||||||
StateData#state.nicks
|
StateData#state.nicks
|
||||||
end,
|
end,
|
||||||
StateData#state{users = Users, nicks = Nicks}.
|
StateData#state{users = Users, nicks = Nicks}.
|
||||||
|
@ -1693,6 +1796,12 @@ get_priority_from_presence(PresencePacket) ->
|
||||||
end
|
end
|
||||||
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) ->
|
is_nick_change(JID, Nick, StateData) ->
|
||||||
LJID = jlib:jid_tolower(JID),
|
LJID = jlib:jid_tolower(JID),
|
||||||
case Nick of
|
case Nick of
|
||||||
|
@ -1726,7 +1835,6 @@ add_new_user(From, Nick, {xmlelement, _, Attrs, Els} = Packet, StateData) ->
|
||||||
mod_muc, max_user_conferences, 10),
|
mod_muc, max_user_conferences, 10),
|
||||||
Collision = nick_collision(From, Nick, StateData),
|
Collision = nick_collision(From, Nick, StateData),
|
||||||
case {(ServiceAffiliation == owner orelse
|
case {(ServiceAffiliation == owner orelse
|
||||||
MaxUsers == none orelse
|
|
||||||
((Affiliation == admin orelse Affiliation == owner) andalso
|
((Affiliation == admin orelse Affiliation == owner) andalso
|
||||||
NUsers < MaxAdminUsers) orelse
|
NUsers < MaxAdminUsers) orelse
|
||||||
NUsers < MaxUsers) andalso
|
NUsers < MaxUsers) andalso
|
||||||
|
@ -2222,7 +2330,7 @@ change_nick(JID, Nick, StateData) ->
|
||||||
?DICT:store(OldNick, OldNickUsers -- [LJID],
|
?DICT:store(OldNick, OldNickUsers -- [LJID],
|
||||||
StateData#state.nicks))
|
StateData#state.nicks))
|
||||||
end,
|
end,
|
||||||
NewStateData = StateData#state{users = Users, nicks = Nicks},
|
NewStateData = StateData#state{users = Users, nicks = Nicks},
|
||||||
send_nick_changing(JID, OldNick, NewStateData, SendOldUnavailable, SendNewAvailable),
|
send_nick_changing(JID, OldNick, NewStateData, SendOldUnavailable, SendNewAvailable),
|
||||||
add_to_log(nickchange, {OldNick, Nick}, StateData),
|
add_to_log(nickchange, {OldNick, Nick}, StateData),
|
||||||
NewStateData.
|
NewStateData.
|
||||||
|
@ -2540,18 +2648,18 @@ process_admin_items_set(UJID, Items, Lang, StateData) ->
|
||||||
{JID, affiliation, outcast, Reason} ->
|
{JID, affiliation, outcast, Reason} ->
|
||||||
catch send_kickban_presence(
|
catch send_kickban_presence(
|
||||||
JID, Reason, "301", outcast, SD),
|
JID, Reason, "301", outcast, SD),
|
||||||
set_affiliation_and_reason(
|
set_affiliation(
|
||||||
JID, outcast, Reason,
|
JID, outcast,
|
||||||
set_role(JID, none, SD));
|
set_role(JID, none, SD), Reason);
|
||||||
{JID, affiliation, A, Reason} when
|
{JID, affiliation, A, Reason} when
|
||||||
(A == admin) or (A == owner) ->
|
(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),
|
SD2 = set_role(JID, moderator, SD1),
|
||||||
send_update_presence(JID, Reason, SD2),
|
send_update_presence(JID, Reason, SD2),
|
||||||
SD2;
|
SD2;
|
||||||
{JID, affiliation, member, Reason} ->
|
{JID, affiliation, member, Reason} ->
|
||||||
SD1 = set_affiliation_and_reason(
|
SD1 = set_affiliation(
|
||||||
JID, member, Reason, SD),
|
JID, member, SD, Reason),
|
||||||
SD2 = set_role(JID, participant, SD1),
|
SD2 = set_role(JID, participant, SD1),
|
||||||
send_update_presence(JID, Reason, SD2),
|
send_update_presence(JID, Reason, SD2),
|
||||||
SD2;
|
SD2;
|
||||||
|
@ -2572,7 +2680,7 @@ process_admin_items_set(UJID, Items, Lang, StateData) ->
|
||||||
NSD ->
|
NSD ->
|
||||||
NSD
|
NSD
|
||||||
end
|
end
|
||||||
end, StateData, Res),
|
end, StateData, lists:flatten(Res)),
|
||||||
case (NSD#state.config)#config.persistent of
|
case (NSD#state.config)#config.persistent of
|
||||||
true ->
|
true ->
|
||||||
mod_muc:store_room(NSD#state.host, NSD#state.room,
|
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]),
|
"Jabber ID ~s is invalid"), [S]),
|
||||||
{error, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)};
|
{error, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)};
|
||||||
J ->
|
J ->
|
||||||
{value, J}
|
{value, [J]}
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
case xml:get_attr("nick", Attrs) of
|
case xml:get_attr("nick", Attrs) of
|
||||||
{value, N} ->
|
{value, N} ->
|
||||||
case find_jid_by_nick(N, StateData) of
|
case find_jids_by_nick(N, StateData) of
|
||||||
false ->
|
false ->
|
||||||
ErrText =
|
ErrText =
|
||||||
io_lib:format(
|
io_lib:format(
|
||||||
|
@ -2626,7 +2734,7 @@ find_changed_items(UJID, UAffiliation, URole,
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
case TJID of
|
case TJID of
|
||||||
{value, JID} ->
|
{value, [JID|_]=JIDs} ->
|
||||||
TAffiliation = get_affiliation(JID, StateData),
|
TAffiliation = get_affiliation(JID, StateData),
|
||||||
TRole = get_role(JID, StateData),
|
TRole = get_role(JID, StateData),
|
||||||
case xml:get_attr("role", Attrs) of
|
case xml:get_attr("role", Attrs) of
|
||||||
|
@ -2676,16 +2784,13 @@ find_changed_items(UJID, UAffiliation, URole,
|
||||||
Items, Lang, StateData,
|
Items, Lang, StateData,
|
||||||
Res);
|
Res);
|
||||||
true ->
|
true ->
|
||||||
|
Reason = xml:get_path_s(Item, [{elem, "reason"}, cdata]),
|
||||||
|
MoreRes = [{jlib:jid_remove_resource(Jidx), affiliation, SAffiliation, Reason} || Jidx <- JIDs],
|
||||||
find_changed_items(
|
find_changed_items(
|
||||||
UJID,
|
UJID,
|
||||||
UAffiliation, URole,
|
UAffiliation, URole,
|
||||||
Items, Lang, StateData,
|
Items, Lang, StateData,
|
||||||
[{jlib:jid_remove_resource(JID),
|
[MoreRes | Res]);
|
||||||
affiliation,
|
|
||||||
SAffiliation,
|
|
||||||
xml:get_path_s(
|
|
||||||
Item, [{elem, "reason"},
|
|
||||||
cdata])} | Res]);
|
|
||||||
false ->
|
false ->
|
||||||
{error, ?ERR_NOT_ALLOWED}
|
{error, ?ERR_NOT_ALLOWED}
|
||||||
end
|
end
|
||||||
|
@ -2733,14 +2838,13 @@ find_changed_items(UJID, UAffiliation, URole,
|
||||||
Items, Lang, StateData,
|
Items, Lang, StateData,
|
||||||
Res);
|
Res);
|
||||||
true ->
|
true ->
|
||||||
|
Reason = xml:get_path_s(Item, [{elem, "reason"}, cdata]),
|
||||||
|
MoreRes = [{Jidx, role, SRole, Reason} || Jidx <- JIDs],
|
||||||
find_changed_items(
|
find_changed_items(
|
||||||
UJID,
|
UJID,
|
||||||
UAffiliation, URole,
|
UAffiliation, URole,
|
||||||
Items, Lang, StateData,
|
Items, Lang, StateData,
|
||||||
[{JID, role, SRole,
|
[MoreRes | Res]);
|
||||||
xml:get_path_s(
|
|
||||||
Item, [{elem, "reason"},
|
|
||||||
cdata])} | Res]);
|
|
||||||
_ ->
|
_ ->
|
||||||
{error, ?ERR_NOT_ALLOWED}
|
{error, ?ERR_NOT_ALLOWED}
|
||||||
end
|
end
|
||||||
|
@ -3291,7 +3395,13 @@ get_config(Lang, StateData, From) ->
|
||||||
Config#config.allow_visitor_status),
|
Config#config.allow_visitor_status),
|
||||||
?BOOLXFIELD("Allow visitors to change nickname",
|
?BOOLXFIELD("Allow visitors to change nickname",
|
||||||
"muc#roomconfig_allowvisitornickchange",
|
"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
|
case ejabberd_captcha:is_feature_available() of
|
||||||
true ->
|
true ->
|
||||||
|
@ -3434,12 +3544,16 @@ set_xoption([{"muc#roomconfig_roomsecret", [Val]} | Opts], Config) ->
|
||||||
?SET_STRING_XOPT(password, Val);
|
?SET_STRING_XOPT(password, Val);
|
||||||
set_xoption([{"anonymous", [Val]} | Opts], Config) ->
|
set_xoption([{"anonymous", [Val]} | Opts], Config) ->
|
||||||
?SET_BOOL_XOPT(anonymous, Val);
|
?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) ->
|
set_xoption([{"muc#roomconfig_whois", [Val]} | Opts], Config) ->
|
||||||
case Val of
|
case Val of
|
||||||
"moderators" ->
|
"moderators" ->
|
||||||
?SET_BOOL_XOPT(anonymous, "1");
|
?SET_BOOL_XOPT(anonymous, integer_to_list(1));
|
||||||
"anyone" ->
|
"anyone" ->
|
||||||
?SET_BOOL_XOPT(anonymous, "0");
|
?SET_BOOL_XOPT(anonymous, integer_to_list(0));
|
||||||
_ ->
|
_ ->
|
||||||
{error, ?ERR_BAD_REQUEST}
|
{error, ?ERR_BAD_REQUEST}
|
||||||
end;
|
end;
|
||||||
|
@ -3526,6 +3640,8 @@ set_opts([{Opt, Val} | Opts], StateData) ->
|
||||||
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)}};
|
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 ->
|
max_users ->
|
||||||
ServiceMaxUsers = get_service_max_users(StateData),
|
ServiceMaxUsers = get_service_max_users(StateData),
|
||||||
MaxUsers = if
|
MaxUsers = if
|
||||||
|
@ -3571,6 +3687,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),
|
||||||
|
?MAKE_CONFIG_OPT(allow_voice_requests),
|
||||||
|
?MAKE_CONFIG_OPT(voice_request_min_interval),
|
||||||
{captcha_whitelist,
|
{captcha_whitelist,
|
||||||
?SETS:to_list((StateData#state.config)#config.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)},
|
||||||
|
@ -3732,9 +3850,136 @@ get_mucroom_disco_items(StateData) ->
|
||||||
end,
|
end,
|
||||||
?DICT:to_list(StateData#state.users)).
|
?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
|
% 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) ->
|
check_invitation(From, Els, Lang, StateData) ->
|
||||||
FAffiliation = get_affiliation(From, StateData),
|
FAffiliation = get_affiliation(From, StateData),
|
||||||
CanInvite = (StateData#state.config)#config.allow_user_invites
|
CanInvite = (StateData#state.config)#config.allow_user_invites
|
||||||
|
|
|
@ -45,6 +45,8 @@
|
||||||
password_protected = false,
|
password_protected = false,
|
||||||
password = "",
|
password = "",
|
||||||
anonymous = true,
|
anonymous = true,
|
||||||
|
allow_voice_requests = true,
|
||||||
|
voice_request_min_interval = 1800,
|
||||||
max_users = ?MAX_USERS_DEFAULT,
|
max_users = ?MAX_USERS_DEFAULT,
|
||||||
logging = false,
|
logging = false,
|
||||||
captcha_whitelist = ?SETS:empty()
|
captcha_whitelist = ?SETS:empty()
|
||||||
|
@ -69,6 +71,7 @@
|
||||||
jid,
|
jid,
|
||||||
config = #config{},
|
config = #config{},
|
||||||
users = ?DICT:new(),
|
users = ?DICT:new(),
|
||||||
|
last_voice_request_time = treap:empty(),
|
||||||
robots = ?DICT:new(),
|
robots = ?DICT:new(),
|
||||||
nicks = ?DICT:new(),
|
nicks = ?DICT:new(),
|
||||||
affiliations = ?DICT:new(),
|
affiliations = ?DICT:new(),
|
||||||
|
|
|
@ -2113,8 +2113,11 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) ->
|
||||||
PluginPayload -> PluginPayload
|
PluginPayload -> PluginPayload
|
||||||
end,
|
end,
|
||||||
ejabberd_hooks:run(pubsub_publish_item, ServerHost, [ServerHost, Node, Publisher, service_jid(Host), ItemId, BrPayload]),
|
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, BrPayload),
|
||||||
set_cached_item(Host, NodeId, ItemId, Publisher, Payload),
|
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
|
case Result of
|
||||||
default -> {result, Reply};
|
default -> {result, Reply};
|
||||||
_ -> {result, Result}
|
_ -> {result, Result}
|
||||||
|
@ -2145,8 +2148,10 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) ->
|
||||||
case lists:member("auto-create", features(Type)) of
|
case lists:member("auto-create", features(Type)) of
|
||||||
true ->
|
true ->
|
||||||
case create_node(Host, ServerHost, Node, Publisher, Type) of
|
case create_node(Host, ServerHost, Node, Publisher, Type) of
|
||||||
{result, _} ->
|
{result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}],
|
||||||
publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload);
|
[{xmlelement, "create", [{"node", NewNode}], []}]}]} ->
|
||||||
|
publish_item(Host, ServerHost, list_to_binary(NewNode),
|
||||||
|
Publisher, ItemId, Payload);
|
||||||
_ ->
|
_ ->
|
||||||
{error, ?ERR_ITEM_NOT_FOUND}
|
{error, ?ERR_ITEM_NOT_FOUND}
|
||||||
end;
|
end;
|
||||||
|
|
|
@ -1880,8 +1880,11 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) ->
|
||||||
PluginPayload -> PluginPayload
|
PluginPayload -> PluginPayload
|
||||||
end,
|
end,
|
||||||
ejabberd_hooks:run(pubsub_publish_item, ServerHost, [ServerHost, Node, Publisher, service_jid(Host), ItemId, BrPayload]),
|
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, BrPayload),
|
||||||
set_cached_item(Host, NodeId, ItemId, Publisher, Payload),
|
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
|
case Result of
|
||||||
default -> {result, Reply};
|
default -> {result, Reply};
|
||||||
_ -> {result, Result}
|
_ -> {result, Result}
|
||||||
|
@ -1912,8 +1915,10 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) ->
|
||||||
case lists:member("auto-create", features(Type)) of
|
case lists:member("auto-create", features(Type)) of
|
||||||
true ->
|
true ->
|
||||||
case create_node(Host, ServerHost, Node, Publisher, Type) of
|
case create_node(Host, ServerHost, Node, Publisher, Type) of
|
||||||
{result, _} ->
|
{result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}],
|
||||||
publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload);
|
[{xmlelement, "create", [{"node", NewNode}], []}]}]} ->
|
||||||
|
publish_item(Host, ServerHost, list_to_binary(NewNode),
|
||||||
|
Publisher, ItemId, Payload);
|
||||||
_ ->
|
_ ->
|
||||||
{error, ?ERR_ITEM_NOT_FOUND}
|
{error, ?ERR_ITEM_NOT_FOUND}
|
||||||
end;
|
end;
|
||||||
|
|
|
@ -136,10 +136,7 @@ create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) ->
|
||||||
{result, Allowed}.
|
{result, Allowed}.
|
||||||
|
|
||||||
create_node(NodeId, Owner) ->
|
create_node(NodeId, Owner) ->
|
||||||
case node_hometree:create_node(NodeId, Owner) of
|
node_hometree:create_node(NodeId, Owner).
|
||||||
{result, _} -> {result, []};
|
|
||||||
Error -> Error
|
|
||||||
end.
|
|
||||||
|
|
||||||
delete_node(Removed) ->
|
delete_node(Removed) ->
|
||||||
case node_hometree:delete_node(Removed) of
|
case node_hometree:delete_node(Removed) of
|
||||||
|
|
|
@ -215,7 +215,7 @@ get_entity_subscriptions(_Host, Owner) ->
|
||||||
{selected, ["host", "node", "type", "nodeid", "jid", "subscriptions"], RItems} ->
|
{selected, ["host", "node", "type", "nodeid", "jid", "subscriptions"], RItems} ->
|
||||||
lists:map(fun({H, N, T, I, J, S}) ->
|
lists:map(fun({H, N, T, I, J, S}) ->
|
||||||
O = node_hometree_odbc:decode_jid(H),
|
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)}
|
{Node, node_hometree_odbc:decode_subscriptions(S), node_hometree_odbc:decode_jid(J)}
|
||||||
end, RItems);
|
end, RItems);
|
||||||
_ ->
|
_ ->
|
||||||
|
@ -249,7 +249,7 @@ get_entity_subscriptions_for_send_last(_Host, Owner) ->
|
||||||
{selected, ["host", "node", "type", "nodeid", "jid", "subscriptions"], RItems} ->
|
{selected, ["host", "node", "type", "nodeid", "jid", "subscriptions"], RItems} ->
|
||||||
lists:map(fun({H, N, T, I, J, S}) ->
|
lists:map(fun({H, N, T, I, J, S}) ->
|
||||||
O = node_hometree_odbc:decode_jid(H),
|
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)}
|
{Node, node_hometree_odbc:decode_subscriptions(S), node_hometree_odbc:decode_jid(J)}
|
||||||
end, RItems);
|
end, RItems);
|
||||||
_ ->
|
_ ->
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
--- mod_pubsub.erl 2011-08-29 09:35:41.000000000 +0200
|
--- mod_pubsub.erl 2011-09-30 13:59:23.000000000 +0200
|
||||||
+++ mod_pubsub_odbc.erl 2011-09-26 16:35:05.000000000 +0200
|
+++ mod_pubsub_odbc.erl 2011-09-30 14:04:34.000000000 +0200
|
||||||
@@ -42,7 +42,7 @@
|
@@ -42,7 +42,7 @@
|
||||||
%%% 6.2.3.1, 6.2.3.5, and 6.3. For information on subscription leases see
|
%%% 6.2.3.1, 6.2.3.5, and 6.3. For information on subscription leases see
|
||||||
%%% XEP-0060 section 12.18.
|
%%% XEP-0060 section 12.18.
|
||||||
|
@ -580,7 +580,7 @@
|
||||||
{PresenceSubscription, RosterGroup} = get_presence_and_roster_permissions(Host, Subscriber, Owners, AccessModel, AllowedGroups),
|
{PresenceSubscription, RosterGroup} = get_presence_and_roster_permissions(Host, Subscriber, Owners, AccessModel, AllowedGroups),
|
||||||
if
|
if
|
||||||
not SubscribeFeature ->
|
not SubscribeFeature ->
|
||||||
@@ -2278,7 +2045,7 @@
|
@@ -2283,7 +2050,7 @@
|
||||||
%% <p>The permission are not checked in this function.</p>
|
%% <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
|
%% @todo We probably need to check that the user doing the query has the right
|
||||||
%% to read the items.
|
%% to read the items.
|
||||||
|
@ -589,7 +589,7 @@
|
||||||
MaxItems =
|
MaxItems =
|
||||||
if
|
if
|
||||||
SMaxItems == "" -> get_max_items_node(Host);
|
SMaxItems == "" -> get_max_items_node(Host);
|
||||||
@@ -2292,12 +2059,13 @@
|
@@ -2297,12 +2064,13 @@
|
||||||
{error, Error} ->
|
{error, Error} ->
|
||||||
{error, Error};
|
{error, Error};
|
||||||
_ ->
|
_ ->
|
||||||
|
@ -604,7 +604,7 @@
|
||||||
{PresenceSubscription, RosterGroup} = get_presence_and_roster_permissions(Host, From, Owners, AccessModel, AllowedGroups),
|
{PresenceSubscription, RosterGroup} = get_presence_and_roster_permissions(Host, From, Owners, AccessModel, AllowedGroups),
|
||||||
if
|
if
|
||||||
not RetreiveFeature ->
|
not RetreiveFeature ->
|
||||||
@@ -2310,11 +2078,11 @@
|
@@ -2315,11 +2083,11 @@
|
||||||
node_call(Type, get_items,
|
node_call(Type, get_items,
|
||||||
[NodeId, From,
|
[NodeId, From,
|
||||||
AccessModel, PresenceSubscription, RosterGroup,
|
AccessModel, PresenceSubscription, RosterGroup,
|
||||||
|
@ -618,7 +618,7 @@
|
||||||
SendItems = case ItemIDs of
|
SendItems = case ItemIDs of
|
||||||
[] ->
|
[] ->
|
||||||
Items;
|
Items;
|
||||||
@@ -2327,7 +2095,8 @@
|
@@ -2332,7 +2100,8 @@
|
||||||
%% number of items sent to MaxItems:
|
%% number of items sent to MaxItems:
|
||||||
{result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}],
|
{result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}],
|
||||||
[{xmlelement, "items", nodeAttr(Node),
|
[{xmlelement, "items", nodeAttr(Node),
|
||||||
|
@ -628,7 +628,7 @@
|
||||||
Error ->
|
Error ->
|
||||||
Error
|
Error
|
||||||
end
|
end
|
||||||
@@ -2349,10 +2118,15 @@
|
@@ -2354,10 +2123,15 @@
|
||||||
Error -> Error
|
Error -> Error
|
||||||
end.
|
end.
|
||||||
get_allowed_items_call(Host, NodeIdx, From, Type, Options, Owners) ->
|
get_allowed_items_call(Host, NodeIdx, From, Type, Options, Owners) ->
|
||||||
|
@ -645,7 +645,7 @@
|
||||||
|
|
||||||
|
|
||||||
%% @spec (Host, Node, NodeId, Type, LJID, Number) -> any()
|
%% @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>
|
%% @doc <p>Resend the items of a node to the user.</p>
|
||||||
%% @todo use cache-last-item feature
|
%% @todo use cache-last-item feature
|
||||||
send_items(Host, Node, NodeId, Type, {U,S,R} = LJID, last) ->
|
send_items(Host, Node, NodeId, Type, {U,S,R} = LJID, last) ->
|
||||||
|
@ -689,7 +689,7 @@
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
send_items(Host, Node, NodeId, Type, {U,S,R} = LJID, Number) ->
|
send_items(Host, Node, NodeId, Type, {U,S,R} = LJID, Number) ->
|
||||||
@@ -2526,7 +2300,8 @@
|
@@ -2531,7 +2305,8 @@
|
||||||
error ->
|
error ->
|
||||||
{error, ?ERR_BAD_REQUEST};
|
{error, ?ERR_BAD_REQUEST};
|
||||||
_ ->
|
_ ->
|
||||||
|
@ -699,7 +699,7 @@
|
||||||
case lists:member(Owner, Owners) of
|
case lists:member(Owner, Owners) of
|
||||||
true ->
|
true ->
|
||||||
OwnerJID = jlib:make_jid(Owner),
|
OwnerJID = jlib:make_jid(Owner),
|
||||||
@@ -2536,24 +2311,7 @@
|
@@ -2541,24 +2316,7 @@
|
||||||
end,
|
end,
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun({JID, Affiliation}) ->
|
fun({JID, Affiliation}) ->
|
||||||
|
@ -725,7 +725,7 @@
|
||||||
end, FilteredEntities),
|
end, FilteredEntities),
|
||||||
{result, []};
|
{result, []};
|
||||||
_ ->
|
_ ->
|
||||||
@@ -2606,9 +2364,9 @@
|
@@ -2611,9 +2369,9 @@
|
||||||
end.
|
end.
|
||||||
|
|
||||||
read_sub(Subscriber, Node, NodeID, SubID, Lang) ->
|
read_sub(Subscriber, Node, NodeID, SubID, Lang) ->
|
||||||
|
@ -737,7 +737,7 @@
|
||||||
OptionsEl = {xmlelement, "options", [{"jid", jlib:jid_to_string(Subscriber)},
|
OptionsEl = {xmlelement, "options", [{"jid", jlib:jid_to_string(Subscriber)},
|
||||||
{"subid", SubID}|nodeAttr(Node)],
|
{"subid", SubID}|nodeAttr(Node)],
|
||||||
[XdataEl]},
|
[XdataEl]},
|
||||||
@@ -2640,7 +2398,7 @@
|
@@ -2645,7 +2403,7 @@
|
||||||
end.
|
end.
|
||||||
|
|
||||||
set_options_helper(Configuration, JID, NodeID, SubID, Type) ->
|
set_options_helper(Configuration, JID, NodeID, SubID, Type) ->
|
||||||
|
@ -746,7 +746,7 @@
|
||||||
{result, GoodSubOpts} -> GoodSubOpts;
|
{result, GoodSubOpts} -> GoodSubOpts;
|
||||||
_ -> invalid
|
_ -> invalid
|
||||||
end,
|
end,
|
||||||
@@ -2839,8 +2597,8 @@
|
@@ -2844,8 +2602,8 @@
|
||||||
{"subscription", subscription_to_string(Sub)} | nodeAttr(Node)], []}]}]},
|
{"subscription", subscription_to_string(Sub)} | nodeAttr(Node)], []}]}]},
|
||||||
ejabberd_router:route(service_jid(Host), jlib:make_jid(JID), Stanza)
|
ejabberd_router:route(service_jid(Host), jlib:make_jid(JID), Stanza)
|
||||||
end,
|
end,
|
||||||
|
@ -757,7 +757,7 @@
|
||||||
true ->
|
true ->
|
||||||
Result = lists:foldl(fun({JID, Subscription, SubId}, Acc) ->
|
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)]),
|
Collection = tree_call(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)]),
|
||||||
{result, [{Depth, [{N, sub_with_options(N)} || N <- Nodes]} || {Depth, Nodes} <- Collection]}
|
{result, [{Depth, [{N, sub_with_options(N)} || N <- Nodes]} || {Depth, Nodes} <- Collection]}
|
||||||
end,
|
end,
|
||||||
|
@ -766,7 +766,7 @@
|
||||||
{result, CollSubs} -> subscribed_nodes_by_jid(NotifyType, CollSubs);
|
{result, CollSubs} -> subscribed_nodes_by_jid(NotifyType, CollSubs);
|
||||||
_ -> []
|
_ -> []
|
||||||
end.
|
end.
|
||||||
@@ -3272,8 +3030,8 @@
|
@@ -3277,8 +3035,8 @@
|
||||||
[]
|
[]
|
||||||
end.
|
end.
|
||||||
sub_with_options(JID, NodeId, SubId) ->
|
sub_with_options(JID, NodeId, SubId) ->
|
||||||
|
@ -777,7 +777,7 @@
|
||||||
_ -> {JID, SubId, []}
|
_ -> {JID, SubId, []}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
@@ -3349,6 +3107,30 @@
|
@@ -3354,6 +3112,30 @@
|
||||||
Result
|
Result
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -808,7 +808,7 @@
|
||||||
%% @spec (Host, Options) -> MaxItems
|
%% @spec (Host, Options) -> MaxItems
|
||||||
%% Host = host()
|
%% Host = host()
|
||||||
%% Options = [Option]
|
%% Options = [Option]
|
||||||
@@ -3479,7 +3261,7 @@
|
@@ -3484,7 +3266,7 @@
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
case transaction(Host, Node, Action, transaction) of
|
case transaction(Host, Node, Action, transaction) of
|
||||||
|
@ -817,7 +817,7 @@
|
||||||
NodeId = TNode#pubsub_node.id,
|
NodeId = TNode#pubsub_node.id,
|
||||||
Type = TNode#pubsub_node.type,
|
Type = TNode#pubsub_node.type,
|
||||||
Options = TNode#pubsub_node.options,
|
Options = TNode#pubsub_node.options,
|
||||||
@@ -3745,7 +3527,13 @@
|
@@ -3750,7 +3532,13 @@
|
||||||
tree_action(Host, Function, Args) ->
|
tree_action(Host, Function, Args) ->
|
||||||
?DEBUG("tree_action ~p ~p ~p",[Host,Function,Args]),
|
?DEBUG("tree_action ~p ~p ~p",[Host,Function,Args]),
|
||||||
Fun = fun() -> tree_call(Host, Function, Args) end,
|
Fun = fun() -> tree_call(Host, Function, Args) end,
|
||||||
|
@ -832,7 +832,7 @@
|
||||||
|
|
||||||
%% @doc <p>node plugin call.</p>
|
%% @doc <p>node plugin call.</p>
|
||||||
node_call(Type, Function, Args) ->
|
node_call(Type, Function, Args) ->
|
||||||
@@ -3765,13 +3553,13 @@
|
@@ -3770,13 +3558,13 @@
|
||||||
|
|
||||||
node_action(Host, Type, Function, Args) ->
|
node_action(Host, Type, Function, Args) ->
|
||||||
?DEBUG("node_action ~p ~p ~p ~p",[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
|
case tree_call(Host, get_node, [Host, Node]) of
|
||||||
N when is_record(N, pubsub_node) ->
|
N when is_record(N, pubsub_node) ->
|
||||||
case Action(N) of
|
case Action(N) of
|
||||||
@@ -3783,13 +3571,19 @@
|
@@ -3788,13 +3576,19 @@
|
||||||
Error
|
Error
|
||||||
end
|
end
|
||||||
end, Trans).
|
end, Trans).
|
||||||
|
@ -872,7 +872,7 @@
|
||||||
{result, Result} -> {result, Result};
|
{result, Result} -> {result, Result};
|
||||||
{error, Error} -> {error, Error};
|
{error, Error} -> {error, Error};
|
||||||
{atomic, {result, Result}} -> {result, Result};
|
{atomic, {result, Result}} -> {result, Result};
|
||||||
@@ -3797,6 +3591,15 @@
|
@@ -3802,6 +3596,15 @@
|
||||||
{aborted, Reason} ->
|
{aborted, Reason} ->
|
||||||
?ERROR_MSG("transaction return internal error: ~p~n", [{aborted, Reason}]),
|
?ERROR_MSG("transaction return internal error: ~p~n", [{aborted, Reason}]),
|
||||||
{error, ?ERR_INTERNAL_SERVER_ERROR};
|
{error, ?ERR_INTERNAL_SERVER_ERROR};
|
||||||
|
@ -888,7 +888,7 @@
|
||||||
{'EXIT', Reason} ->
|
{'EXIT', Reason} ->
|
||||||
?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]),
|
?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]),
|
||||||
{error, ?ERR_INTERNAL_SERVER_ERROR};
|
{error, ?ERR_INTERNAL_SERVER_ERROR};
|
||||||
@@ -3805,6 +3608,17 @@
|
@@ -3810,6 +3613,17 @@
|
||||||
{error, ?ERR_INTERNAL_SERVER_ERROR}
|
{error, ?ERR_INTERNAL_SERVER_ERROR}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
-behaviour(gen_mod).
|
-behaviour(gen_mod).
|
||||||
|
|
||||||
-export([start/2, stop/1,
|
-export([start/2, stop/1,
|
||||||
|
item_to_xml/1,
|
||||||
webadmin_menu/3, webadmin_page/3,
|
webadmin_menu/3, webadmin_page/3,
|
||||||
get_user_roster/2,
|
get_user_roster/2,
|
||||||
get_subscription_lists/3,
|
get_subscription_lists/3,
|
||||||
|
@ -616,14 +617,15 @@ add_user_to_group(Host, US, Group) ->
|
||||||
case regexp:match(LUser, "^@.+@$") of
|
case regexp:match(LUser, "^@.+@$") of
|
||||||
{match,_,_} ->
|
{match,_,_} ->
|
||||||
GroupOpts = mod_shared_roster:get_group_opts(Host, Group),
|
GroupOpts = mod_shared_roster:get_group_opts(Host, Group),
|
||||||
AllUsersOpt =
|
MoreGroupOpts =
|
||||||
case LUser == "@all@" of
|
case LUser of
|
||||||
true -> [{all_users, true}];
|
"@all@" -> [{all_users, true}];
|
||||||
false -> []
|
"@online@" -> [{online_users, true}];
|
||||||
|
_ -> []
|
||||||
end,
|
end,
|
||||||
mod_shared_roster:set_group_opts(
|
mod_shared_roster:set_group_opts(
|
||||||
Host, Group,
|
Host, Group,
|
||||||
GroupOpts ++ AllUsersOpt);
|
GroupOpts ++ MoreGroupOpts);
|
||||||
nomatch ->
|
nomatch ->
|
||||||
%% Push this new user to members of groups where this group is displayed
|
%% Push this new user to members of groups where this group is displayed
|
||||||
push_user_to_displayed(LUser, LServer, Group, both),
|
push_user_to_displayed(LUser, LServer, Group, both),
|
||||||
|
@ -651,7 +653,9 @@ remove_user_from_group(Host, US, Group) ->
|
||||||
NewGroupOpts =
|
NewGroupOpts =
|
||||||
case LUser of
|
case LUser of
|
||||||
"@all@" ->
|
"@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,
|
end,
|
||||||
mod_shared_roster:set_group_opts(Host, Group, NewGroupOpts);
|
mod_shared_roster:set_group_opts(Host, Group, NewGroupOpts);
|
||||||
nomatch ->
|
nomatch ->
|
||||||
|
@ -726,8 +730,6 @@ displayed_to_groups(GroupName, LServer) ->
|
||||||
lists:member(GroupName, proplists:get_value(displayed_groups, Opts, []))
|
lists:member(GroupName, proplists:get_value(displayed_groups, Opts, []))
|
||||||
end, GroupsOpts).
|
end, GroupsOpts).
|
||||||
|
|
||||||
push_item(_User, _Server, _From, none) ->
|
|
||||||
ok;
|
|
||||||
push_item(User, Server, From, Item) ->
|
push_item(User, Server, From, Item) ->
|
||||||
%% It was
|
%% It was
|
||||||
%% ejabberd_sm:route(jlib:make_jid("", "", ""),
|
%% ejabberd_sm:route(jlib:make_jid("", "", ""),
|
||||||
|
|
|
@ -63,6 +63,7 @@
|
||||||
base,
|
base,
|
||||||
password,
|
password,
|
||||||
uid,
|
uid,
|
||||||
|
deref_aliases,
|
||||||
group_attr,
|
group_attr,
|
||||||
group_desc,
|
group_desc,
|
||||||
user_desc,
|
user_desc,
|
||||||
|
@ -314,6 +315,7 @@ eldap_search(State, FilterParseArgs, AttributesList) ->
|
||||||
[{base, State#state.base},
|
[{base, State#state.base},
|
||||||
{filter, EldapFilter},
|
{filter, EldapFilter},
|
||||||
{timeout, ?LDAP_SEARCH_TIMEOUT},
|
{timeout, ?LDAP_SEARCH_TIMEOUT},
|
||||||
|
{deref_aliases, State#state.deref_aliases},
|
||||||
{attributes, AttributesList}]) of
|
{attributes, AttributesList}]) of
|
||||||
#eldap_search_result{entries = Es} ->
|
#eldap_search_result{entries = Es} ->
|
||||||
%% A result with entries. Return their list.
|
%% A result with entries. Return their list.
|
||||||
|
@ -659,6 +661,15 @@ parse_options(Host, Opts) ->
|
||||||
"" -> GroupSubFilter;
|
"" -> GroupSubFilter;
|
||||||
_ -> "(&" ++ GroupSubFilter ++ ConfigFilter ++ ")"
|
_ -> "(&" ++ GroupSubFilter ++ ConfigFilter ++ ")"
|
||||||
end,
|
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,
|
#state{host = Host,
|
||||||
eldap_id = Eldap_ID,
|
eldap_id = Eldap_ID,
|
||||||
servers = LDAPServers,
|
servers = LDAPServers,
|
||||||
|
@ -672,6 +683,7 @@ parse_options(Host, Opts) ->
|
||||||
base = LDAPBase,
|
base = LDAPBase,
|
||||||
password = Password,
|
password = Password,
|
||||||
uid = UIDAttr,
|
uid = UIDAttr,
|
||||||
|
deref_aliases = DerefAliases,
|
||||||
group_attr = GroupAttr,
|
group_attr = GroupAttr,
|
||||||
group_desc = GroupDesc,
|
group_desc = GroupDesc,
|
||||||
user_desc = UserDesc,
|
user_desc = UserDesc,
|
||||||
|
|
|
@ -167,12 +167,7 @@ get_local_stat(_Server, [], Name) when Name == "users/all-hosts/total" ->
|
||||||
ejabberd_auth:get_vh_registered_users_number(Host)
|
ejabberd_auth:get_vh_registered_users_number(Host)
|
||||||
+ Total
|
+ Total
|
||||||
end, 0, ejabberd_config:get_global_option(hosts)),
|
end, 0, ejabberd_config:get_global_option(hosts)),
|
||||||
case NumUsers of
|
?STATVAL(integer_to_list(NumUsers), "users");
|
||||||
{'EXIT', _Reason} ->
|
|
||||||
?STATERR("500", "Internal Server Error");
|
|
||||||
Users ->
|
|
||||||
?STATVAL(integer_to_list(Users), "users")
|
|
||||||
end;
|
|
||||||
|
|
||||||
get_local_stat(_Server, _, Name) ->
|
get_local_stat(_Server, _, Name) ->
|
||||||
?STATERR("404", "Not Found").
|
?STATERR("404", "Not Found").
|
||||||
|
|
|
@ -74,6 +74,7 @@
|
||||||
search_fields,
|
search_fields,
|
||||||
search_reported,
|
search_reported,
|
||||||
search_reported_attrs,
|
search_reported_attrs,
|
||||||
|
deref_aliases,
|
||||||
matches
|
matches
|
||||||
}).
|
}).
|
||||||
|
|
||||||
|
@ -287,9 +288,11 @@ find_ldap_user(User, State) ->
|
||||||
VCardAttrs = State#state.vcard_map_attrs,
|
VCardAttrs = State#state.vcard_map_attrs,
|
||||||
case eldap_filter:parse(RFC2254_Filter, [{"%u", User}]) of
|
case eldap_filter:parse(RFC2254_Filter, [{"%u", User}]) of
|
||||||
{ok, EldapFilter} ->
|
{ok, EldapFilter} ->
|
||||||
case eldap_pool:search(Eldap_ID, [{base, Base},
|
case eldap_pool:search(Eldap_ID,
|
||||||
{filter, EldapFilter},
|
[{base, Base},
|
||||||
{attributes, VCardAttrs}]) of
|
{filter, EldapFilter},
|
||||||
|
{deref_aliases, State#state.deref_aliases},
|
||||||
|
{attributes, VCardAttrs}]) of
|
||||||
#eldap_search_result{entries = [E | _]} ->
|
#eldap_search_result{entries = [E | _]} ->
|
||||||
E;
|
E;
|
||||||
_ ->
|
_ ->
|
||||||
|
@ -572,10 +575,12 @@ search(State, Data) ->
|
||||||
Limit = State#state.matches,
|
Limit = State#state.matches,
|
||||||
ReportedAttrs = State#state.search_reported_attrs,
|
ReportedAttrs = State#state.search_reported_attrs,
|
||||||
Filter = eldap:'and'([SearchFilter, eldap_utils:make_filter(Data, UIDs)]),
|
Filter = eldap:'and'([SearchFilter, eldap_utils:make_filter(Data, UIDs)]),
|
||||||
case eldap_pool:search(Eldap_ID, [{base, Base},
|
case eldap_pool:search(Eldap_ID,
|
||||||
{filter, Filter},
|
[{base, Base},
|
||||||
{limit, Limit},
|
{filter, Filter},
|
||||||
{attributes, ReportedAttrs}]) of
|
{limit, Limit},
|
||||||
|
{deref_aliases, State#state.deref_aliases},
|
||||||
|
{attributes, ReportedAttrs}]) of
|
||||||
#eldap_search_result{entries = E} ->
|
#eldap_search_result{entries = E} ->
|
||||||
search_items(E, State);
|
search_items(E, State);
|
||||||
_ ->
|
_ ->
|
||||||
|
@ -779,6 +784,15 @@ parse_options(Host, Opts) ->
|
||||||
_ -> []
|
_ -> []
|
||||||
end
|
end
|
||||||
end, SearchReported) ++ UIDAttrs),
|
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,
|
#state{serverhost = Host,
|
||||||
myhost = MyHost,
|
myhost = MyHost,
|
||||||
eldap_id = Eldap_ID,
|
eldap_id = Eldap_ID,
|
||||||
|
@ -801,5 +815,6 @@ parse_options(Host, Opts) ->
|
||||||
search_fields = SearchFields,
|
search_fields = SearchFields,
|
||||||
search_reported = SearchReported,
|
search_reported = SearchReported,
|
||||||
search_reported_attrs = SearchReportedAttrs,
|
search_reported_attrs = SearchReportedAttrs,
|
||||||
|
deref_aliases = DerefAliases,
|
||||||
matches = Matches
|
matches = Matches
|
||||||
}.
|
}.
|
||||||
|
|
|
@ -458,7 +458,7 @@ decode_msg(Msg,Parent, Name, StateName, StateData, Mod, Time, Debug,
|
||||||
handle_msg(Msg, Parent, Name, StateName, StateData,
|
handle_msg(Msg, Parent, Name, StateName, StateData,
|
||||||
Mod, Time, Limits, Queue, QueueLen);
|
Mod, Time, Limits, Queue, QueueLen);
|
||||||
_Msg ->
|
_Msg ->
|
||||||
Debug1 = sys:handle_debug(Debug, {?MODULE, print_event},
|
Debug1 = sys:handle_debug(Debug, fun print_event/3,
|
||||||
{Name, StateName}, {in, Msg}),
|
{Name, StateName}, {in, Msg}),
|
||||||
handle_msg(Msg, Parent, Name, StateName, StateData,
|
handle_msg(Msg, Parent, Name, StateName, StateData,
|
||||||
Mod, Time, Debug1, Limits, Queue, QueueLen)
|
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,
|
loop(Parent, Name, StateName, StateData, Mod, Time, Debug,
|
||||||
Limits, Queue, QueueLen).
|
Limits, Queue, QueueLen).
|
||||||
|
|
||||||
|
-spec system_terminate(term(), _, _, [term(),...]) -> no_return().
|
||||||
|
|
||||||
system_terminate(Reason, _Parent, Debug,
|
system_terminate(Reason, _Parent, Debug,
|
||||||
[Name, StateName, StateData, Mod, _Time,
|
[Name, StateName, StateData, Mod, _Time,
|
||||||
_Limits, Queue, _QueueLen]) ->
|
_Limits, Queue, _QueueLen]) ->
|
||||||
|
@ -603,12 +605,12 @@ handle_msg(Msg, Parent, Name, StateName, StateData,
|
||||||
From = from(Msg),
|
From = from(Msg),
|
||||||
case catch dispatch(Msg, Mod, StateName, StateData) of
|
case catch dispatch(Msg, Mod, StateName, StateData) of
|
||||||
{next_state, NStateName, NStateData} ->
|
{next_state, NStateName, NStateData} ->
|
||||||
Debug1 = sys:handle_debug(Debug, {?MODULE, print_event},
|
Debug1 = sys:handle_debug(Debug, fun print_event/3,
|
||||||
{Name, NStateName}, return),
|
{Name, NStateName}, return),
|
||||||
loop(Parent, Name, NStateName, NStateData,
|
loop(Parent, Name, NStateName, NStateData,
|
||||||
Mod, infinity, Debug1, Limits, Queue, QueueLen);
|
Mod, infinity, Debug1, Limits, Queue, QueueLen);
|
||||||
{next_state, NStateName, NStateData, Time1} ->
|
{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),
|
{Name, NStateName}, return),
|
||||||
loop(Parent, Name, NStateName, NStateData,
|
loop(Parent, Name, NStateName, NStateData,
|
||||||
Mod, Time1, Debug1, Limits, Queue, QueueLen);
|
Mod, Time1, Debug1, Limits, Queue, QueueLen);
|
||||||
|
@ -689,7 +691,7 @@ reply({To, Tag}, Reply) ->
|
||||||
|
|
||||||
reply(Name, {To, Tag}, Reply, Debug, StateName) ->
|
reply(Name, {To, Tag}, Reply, Debug, StateName) ->
|
||||||
reply({To, Tag}, Reply),
|
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}).
|
{out, Reply, To, StateName}).
|
||||||
|
|
||||||
%%% ---------------------------------------------------
|
%%% ---------------------------------------------------
|
||||||
|
|
|
@ -37,8 +37,9 @@
|
||||||
client_key/2
|
client_key/2
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
%% ejabberd doesn't implement SASLPREP, so we use the similar RESOURCEPREP instead
|
||||||
salted_password(Password, Salt, IterationCount) ->
|
salted_password(Password, Salt, IterationCount) ->
|
||||||
hi(jlib:nameprep(Password), Salt, IterationCount).
|
hi(jlib:resourceprep(Password), Salt, IterationCount).
|
||||||
|
|
||||||
client_key(SaltedPassword) ->
|
client_key(SaltedPassword) ->
|
||||||
crypto:sha_mac(SaltedPassword, "Client Key").
|
crypto:sha_mac(SaltedPassword, "Client Key").
|
||||||
|
@ -53,29 +54,29 @@ client_signature(StoredKey, AuthMessage) ->
|
||||||
crypto:sha_mac(StoredKey, AuthMessage).
|
crypto:sha_mac(StoredKey, AuthMessage).
|
||||||
|
|
||||||
client_key(ClientProof, ClientSignature) ->
|
client_key(ClientProof, ClientSignature) ->
|
||||||
binary:list_to_bin(lists:zipwith(fun(X, Y) ->
|
list_to_binary(lists:zipwith(fun(X, Y) ->
|
||||||
X bxor Y
|
X bxor Y
|
||||||
end,
|
end,
|
||||||
binary:bin_to_list(ClientProof),
|
binary_to_list(ClientProof),
|
||||||
binary:bin_to_list(ClientSignature))).
|
binary_to_list(ClientSignature))).
|
||||||
|
|
||||||
server_signature(ServerKey, AuthMessage) ->
|
server_signature(ServerKey, AuthMessage) ->
|
||||||
crypto:sha_mac(ServerKey, AuthMessage).
|
crypto:sha_mac(ServerKey, AuthMessage).
|
||||||
|
|
||||||
hi(Password, Salt, IterationCount) ->
|
hi(Password, Salt, IterationCount) ->
|
||||||
U1 = crypto:sha_mac(Password, string:concat(binary:bin_to_list(Salt), [0,0,0,1])),
|
U1 = crypto:sha_mac(Password, string:concat(binary_to_list(Salt), [0,0,0,1])),
|
||||||
binary:list_to_bin(lists:zipwith(fun(X, Y) ->
|
list_to_binary(lists:zipwith(fun(X, Y) ->
|
||||||
X bxor Y
|
X bxor Y
|
||||||
end,
|
end,
|
||||||
binary:bin_to_list(U1),
|
binary_to_list(U1),
|
||||||
binary:bin_to_list(hi_round(Password, U1, IterationCount-1)))).
|
binary_to_list(hi_round(Password, U1, IterationCount-1)))).
|
||||||
|
|
||||||
hi_round(Password, UPrev, 1) ->
|
hi_round(Password, UPrev, 1) ->
|
||||||
crypto:sha_mac(Password, UPrev);
|
crypto:sha_mac(Password, UPrev);
|
||||||
hi_round(Password, UPrev, IterationCount) ->
|
hi_round(Password, UPrev, IterationCount) ->
|
||||||
U = crypto:sha_mac(Password, UPrev),
|
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
|
X bxor Y
|
||||||
end,
|
end,
|
||||||
binary:bin_to_list(U),
|
binary_to_list(U),
|
||||||
binary:bin_to_list(hi_round(Password, U, IterationCount-1)))).
|
binary_to_list(hi_round(Password, U, IterationCount-1)))).
|
||||||
|
|
|
@ -47,7 +47,7 @@ start() ->
|
||||||
end,
|
end,
|
||||||
case Res of
|
case Res of
|
||||||
ok ->
|
ok ->
|
||||||
Port = open_port({spawn, ?DRIVER}, [binary]),
|
Port = open_port({spawn, atom_to_list(?DRIVER)}, [binary]),
|
||||||
register(?DRIVER, Port);
|
register(?DRIVER, Port);
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?CRITICAL_MSG("unable to load driver '~s': ~s",
|
?CRITICAL_MSG("unable to load driver '~s': ~s",
|
||||||
|
|
|
@ -60,7 +60,7 @@ init([]) ->
|
||||||
ok -> ok;
|
ok -> ok;
|
||||||
{error, already_loaded} -> ok
|
{error, already_loaded} -> ok
|
||||||
end,
|
end,
|
||||||
Port = open_port({spawn, stringprep_drv}, []),
|
Port = open_port({spawn, "stringprep_drv"}, []),
|
||||||
register(?STRINGPREP_PORT, Port),
|
register(?STRINGPREP_PORT, Port),
|
||||||
{ok, Port}.
|
{ok, Port}.
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ init([]) ->
|
||||||
ok -> ok;
|
ok -> ok;
|
||||||
{error, already_loaded} -> ok
|
{error, already_loaded} -> ok
|
||||||
end,
|
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]),
|
Res = port_control(Port, ?SET_CERTIFICATE_FILE_ACCEPT, "./ssl.pem" ++ [0]),
|
||||||
case Res of
|
case Res of
|
||||||
<<0>> ->
|
<<0>> ->
|
||||||
|
@ -130,7 +130,7 @@ tcp_to_tls(TCPSocket, Options) ->
|
||||||
ok -> ok;
|
ok -> ok;
|
||||||
{error, already_loaded} -> ok
|
{error, already_loaded} -> ok
|
||||||
end,
|
end,
|
||||||
Port = open_port({spawn, tls_drv}, [binary]),
|
Port = open_port({spawn, "tls_drv"}, [binary]),
|
||||||
Flags =
|
Flags =
|
||||||
case lists:member(verify_none, Options) of
|
case lists:member(verify_none, Options) of
|
||||||
true ->
|
true ->
|
||||||
|
@ -267,7 +267,7 @@ test() ->
|
||||||
ok -> ok;
|
ok -> ok;
|
||||||
{error, already_loaded} -> ok
|
{error, already_loaded} -> ok
|
||||||
end,
|
end,
|
||||||
Port = open_port({spawn, tls_drv}, [binary]),
|
Port = open_port({spawn, "tls_drv"}, [binary]),
|
||||||
?PRINT("open_port: ~p~n", [Port]),
|
?PRINT("open_port: ~p~n", [Port]),
|
||||||
PCRes = port_control(Port, ?SET_CERTIFICATE_FILE_ACCEPT,
|
PCRes = port_control(Port, ?SET_CERTIFICATE_FILE_ACCEPT,
|
||||||
"./ssl.pem" ++ [0]),
|
"./ssl.pem" ++ [0]),
|
||||||
|
|
|
@ -409,20 +409,12 @@ static int tls_drv_control(ErlDrvData handle,
|
||||||
break;
|
break;
|
||||||
case GET_ENCRYPTED_OUTPUT:
|
case GET_ENCRYPTED_OUTPUT:
|
||||||
die_unless(d->ssl, "SSL not initialized");
|
die_unless(d->ssl, "SSL not initialized");
|
||||||
rlen = 1;
|
size = BIO_ctrl_pending(d->bio_write) + 1;
|
||||||
b = driver_alloc_binary(rlen + BUF_SIZE);
|
b = driver_alloc_binary(size);
|
||||||
b->orig_bytes[0] = 0;
|
b->orig_bytes[0] = 0;
|
||||||
while ((res = BIO_read(d->bio_write,
|
BIO_read(d->bio_write, b->orig_bytes + 1, size - 1);
|
||||||
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);
|
|
||||||
*rbuf = (char *)b;
|
*rbuf = (char *)b;
|
||||||
return rlen;
|
return size;
|
||||||
case GET_DECRYPTED_INPUT:
|
case GET_DECRYPTED_INPUT:
|
||||||
if (!SSL_is_init_finished(d->ssl))
|
if (!SSL_is_init_finished(d->ssl))
|
||||||
{
|
{
|
||||||
|
|
|
@ -63,8 +63,6 @@ insert1({HashKey1, Priority1, Value1, Left, Right} = Tree,
|
||||||
insert1(delete_root(Tree), HashKey, Priority, Value)
|
insert1(delete_root(Tree), HashKey, Priority, Value)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
heapify(nil) ->
|
|
||||||
nil;
|
|
||||||
heapify({_HashKey, _Priority, _Value, nil, nil} = Tree) ->
|
heapify({_HashKey, _Priority, _Value, nil, nil} = Tree) ->
|
||||||
Tree;
|
Tree;
|
||||||
heapify({HashKey, Priority, Value,
|
heapify({HashKey, Priority, Value,
|
||||||
|
|
|
@ -409,7 +409,7 @@ process_request(#state{request_method = Method,
|
||||||
when Method=:='GET' orelse Method=:='HEAD' orelse Method=:='DELETE' orelse Method=:='OPTIONS' ->
|
when Method=:='GET' orelse Method=:='HEAD' orelse Method=:='DELETE' orelse Method=:='OPTIONS' ->
|
||||||
case (catch url_decode_q_split(Path)) of
|
case (catch url_decode_q_split(Path)) of
|
||||||
{'EXIT', _} ->
|
{'EXIT', _} ->
|
||||||
process_request(false);
|
make_bad_request(State);
|
||||||
{NPath, Query} ->
|
{NPath, Query} ->
|
||||||
LPath = [path_decode(NPE) || NPE <- string:tokens(NPath, "/")],
|
LPath = [path_decode(NPE) || NPE <- string:tokens(NPath, "/")],
|
||||||
LQuery = case (catch parse_urlencoded(Query)) of
|
LQuery = case (catch parse_urlencoded(Query)) of
|
||||||
|
@ -507,7 +507,7 @@ process_request(#state{request_method = Method,
|
||||||
?DEBUG("client data: ~p~n", [Data]),
|
?DEBUG("client data: ~p~n", [Data]),
|
||||||
case (catch url_decode_q_split(Path)) of
|
case (catch url_decode_q_split(Path)) of
|
||||||
{'EXIT', _} ->
|
{'EXIT', _} ->
|
||||||
process_request(false);
|
make_bad_request(State);
|
||||||
{NPath, _Query} ->
|
{NPath, _Query} ->
|
||||||
LPath = [path_decode(NPE) || NPE <- string:tokens(NPath, "/")],
|
LPath = [path_decode(NPE) || NPE <- string:tokens(NPath, "/")],
|
||||||
LQuery = case (catch parse_urlencoded(Data)) of
|
LQuery = case (catch parse_urlencoded(Data)) of
|
||||||
|
@ -543,6 +543,9 @@ process_request(#state{request_method = Method,
|
||||||
end;
|
end;
|
||||||
|
|
||||||
process_request(State) ->
|
process_request(State) ->
|
||||||
|
make_bad_request(State).
|
||||||
|
|
||||||
|
make_bad_request(State) ->
|
||||||
make_xhtml_output(State,
|
make_xhtml_output(State,
|
||||||
400,
|
400,
|
||||||
[],
|
[],
|
||||||
|
@ -589,7 +592,7 @@ recv_data(State, Len, Acc) ->
|
||||||
end,
|
end,
|
||||||
case (State#state.sockmod):recv(State#state.socket, Len2, 300000) of
|
case (State#state.sockmod):recv(State#state.socket, Len2, 300000) of
|
||||||
{ok, Data} ->
|
{ok, Data} ->
|
||||||
recv_data(State, Len - size(Data), [Acc | Data]);
|
recv_data(State, Len - size(Data), [Acc | [Data]]);
|
||||||
_ ->
|
_ ->
|
||||||
""
|
""
|
||||||
end;
|
end;
|
||||||
|
@ -1179,8 +1182,8 @@ is_space(_) ->
|
||||||
strip_spaces(String) ->
|
strip_spaces(String) ->
|
||||||
strip_spaces(String, both).
|
strip_spaces(String, both).
|
||||||
|
|
||||||
strip_spaces(String, left) ->
|
%% strip_spaces(String, left) ->
|
||||||
drop_spaces(String);
|
%% drop_spaces(String);
|
||||||
strip_spaces(String, right) ->
|
strip_spaces(String, right) ->
|
||||||
lists:reverse(drop_spaces(lists:reverse(String)));
|
lists:reverse(drop_spaces(lists:reverse(String)));
|
||||||
strip_spaces(String, both) ->
|
strip_spaces(String, both) ->
|
||||||
|
|
|
@ -106,16 +106,6 @@ get_menu_items(global, cluster, Lang, JID) ->
|
||||||
);
|
);
|
||||||
get_menu_items(Host, cluster, Lang, JID) ->
|
get_menu_items(Host, cluster, Lang, JID) ->
|
||||||
{Base, _, Items} = make_host_menu(Host, [], 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(
|
lists:map(
|
||||||
fun({URI, Name}) ->
|
fun({URI, Name}) ->
|
||||||
{Base++URI++"/", Name};
|
{Base++URI++"/", Name};
|
||||||
|
@ -124,6 +114,16 @@ get_menu_items(Host, Node, Lang, JID) ->
|
||||||
end,
|
end,
|
||||||
Items
|
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) ->
|
||||||
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) ->
|
get_node(global, Node, ["backup"], Query, Lang) ->
|
||||||
HomeDirRaw = case {os:getenv("HOME"), os:type()} of
|
HomeDirRaw = case {os:getenv("HOME"), os:type()} of
|
||||||
{EnvHome, _} when is_list(EnvHome) -> EnvHome;
|
{EnvHome, _} when is_list(EnvHome) -> EnvHome;
|
||||||
{false, win32} -> "C:/";
|
|
||||||
{false, {win32, _Osname}} -> "C:/";
|
{false, {win32, _Osname}} -> "C:/";
|
||||||
{false, _} -> "/tmp/"
|
{false, _} -> "/tmp/"
|
||||||
end,
|
end,
|
||||||
|
|
|
@ -61,9 +61,10 @@
|
||||||
{".html", "text/html"},
|
{".html", "text/html"},
|
||||||
{".jar", "application/java-archive"},
|
{".jar", "application/java-archive"},
|
||||||
{".jpeg", "image/jpeg"},
|
{".jpeg", "image/jpeg"},
|
||||||
{".jpg", "image/jpeg"},
|
{".jpg", "image/jpeg"},
|
||||||
{".js", "text/javascript"},
|
{".js", "text/javascript"},
|
||||||
{".png", "image/png"},
|
{".png", "image/png"},
|
||||||
|
{".svg", "image/svg+xml"},
|
||||||
{".txt", "text/plain"},
|
{".txt", "text/plain"},
|
||||||
{".xml", "application/xml"},
|
{".xml", "application/xml"},
|
||||||
{".xpi", "application/x-xpinstall"},
|
{".xpi", "application/x-xpinstall"},
|
||||||
|
|
|
@ -104,7 +104,7 @@ new(CallbackPid) ->
|
||||||
new(CallbackPid, infinity).
|
new(CallbackPid, infinity).
|
||||||
|
|
||||||
new(CallbackPid, MaxSize) ->
|
new(CallbackPid, MaxSize) ->
|
||||||
Port = open_port({spawn, expat_erl}, [binary]),
|
Port = open_port({spawn, "expat_erl"}, [binary]),
|
||||||
#xml_stream_state{callback_pid = CallbackPid,
|
#xml_stream_state{callback_pid = CallbackPid,
|
||||||
port = Port,
|
port = Port,
|
||||||
stack = [],
|
stack = [],
|
||||||
|
@ -147,7 +147,7 @@ close(#xml_stream_state{port = Port}) ->
|
||||||
|
|
||||||
|
|
||||||
parse_element(Str) ->
|
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),
|
Res = port_control(Port, ?PARSE_FINAL_COMMAND, Str),
|
||||||
port_close(Port),
|
port_close(Port),
|
||||||
process_element_events(binary_to_term(Res)).
|
process_element_events(binary_to_term(Res)).
|
||||||
|
|
Loading…
Reference in New Issue
Block a user