Compare commits

...

43 Commits

Author SHA1 Message Date
Christophe Romain a8e49ed5ee tag for 2.0.5
SVN Revision: 2003
2009-04-01 15:05:29 +00:00
Badlop 3991450318 * doc/release_notes_2.0.5.txt: Added file for new release
SVN Revision: 2002
2009-04-01 10:37:18 +00:00
Badlop 1f3acfc83f * src/expat_erl.c: Fix implicit declaration of function
x_fix_buff (thanks to Dennis Schridde)(EJAB-900)

SVN Revision: 2000
2009-03-24 23:09:46 +00:00
Badlop 1e3faf8bd9 Merge 1998 from trunk.
* src/ejabberd_sm.erl: Partially retract SVN r1976
EJAB-300 (EJAB-890). Check default privacy list when account, not
a specific session, receives a presence subscription
stanza (EJAB-300).
* src/ejabberd_c2s.erl: Likewise

SVN Revision: 1999
2009-03-24 18:02:13 +00:00
Badlop 3fce8ed570 Fix mistake when calling win32_dns.
SVN Revision: 1990
2009-03-11 18:36:27 +00:00
Christophe Romain b6abe1b926 fix typo in previous patch backport
SVN Revision: 1988
2009-03-10 21:10:42 +00:00
Badlop 69b11b677d * doc/release_notes_2.0.4.txt: Added file for new release
SVN Revision: 1987
2009-03-10 16:25:20 +00:00
Badlop 8f41436cd8 * src/tls/tls_drv.c: Fix encryption problem for ejabberd_http
after timeout (thanks to Alexey Shchepin)(EJAB-880)

SVN Revision: 1986
2009-03-10 15:21:36 +00:00
Christophe Romain b0864396ec typo fix on roster access_model
SVN Revision: 1983
2009-03-10 12:08:12 +00:00
Christophe Romain dcac4ed8c8 Fix PEP with other domains and s2s (EJAB-825)
SVN Revision: 1981
2009-03-10 10:46:19 +00:00
Badlop 74c202a714 * src/tls/tls_drv.c: Fix to support OpenSSL older than
0.9.8f (EJAB-877)(thanks to Jonathan Schleifer)
* doc/guide.tex: It is again supported OpenSSL older than 0.9.8f
* doc/guide.html: Likewise

SVN Revision: 1979
2009-03-09 19:17:53 +00:00
Badlop 10b22b52ef Merge 1925 from trunk.
* src/mod_proxy65/mod_proxy65_service.erl: if an ip option is not
defined, the module takes an IP address of a local
hostname (thanks to Evgeniy Khramtsov)

SVN Revision: 1978
2009-03-09 14:44:46 +00:00
Badlop a6145084f1 * src/ejabberd_c2s.erl: Enforce privacy rules also for
subscription requests (EJAB-300)
* src/ejabberd_sm.erl: Likewise

SVN Revision: 1976
2009-03-07 08:59:26 +00:00
Badlop 367002f89a Merge 1856 from trunk.
* src/eldap/eldap.erl: moves waiting for response queries to
pending queue on an LDAP connection failure (thanks to Evgeniy
Khramtsov)

SVN Revision: 1974
2009-03-06 11:50:23 +00:00
Badlop 75a8ebf293 Merge 1855 from trunk.
* src/eldap/eldap.erl: implemented queue for pending
queries (thanks to Evgeniy Khramtsov)

SVN Revision: 1973
2009-03-06 11:42:56 +00:00
Badlop 4e17b1463b Merge 1851 from trunk.
* src/eldap/eldap.erl: Close a connection on tcp_error (thanks to
Evgeniy Khramtsov)

SVN Revision: 1972
2009-03-06 11:39:12 +00:00
Badlop 5c73d160cc Merge 1682 from trunk.
* src/eldap/Makefile.in: added +optimize and +driver compilation
options (thanks to Evgeniy Khramtsov)
* src/eldap/Makefile.win32: Likewise

SVN Revision: 1971
2009-03-06 11:34:27 +00:00
Badlop ac69fbb24d * src/ejabberd_app.erl: In a Windows machine, explicitly add the
nameservers, as it seems Erlang does not do itself (EJAB-860)
* src/win32_dns.erl: Get name servers from Windows registy (thanks
to Geoff Cant)

SVN Revision: 1968
2009-03-05 20:03:18 +00:00
Badlop 3454f2fe04 * doc/guide.tex: Require OpenSSL 0.9.8f or higher (EJAB-877)
* doc/guide.html: Likewise

SVN Revision: 1967
2009-03-05 19:48:24 +00:00
Badlop 5374c0b069 * src/ejabberd_auth.erl: If anonymous auth is enabled, when
checking if the account already exists in other auth methods, take
into account if the auth method failed (EJAB-882)
* src/ejabberd_auth_anonymous.erl: Likewise
* src/ejabberd_auth_external.erl: Likewise
* src/ejabberd_auth_internal.erl: Likewise
* src/ejabberd_auth_ldap.erl: Likewise
* src/ejabberd_auth_odbc.erl: Likewise
* src/ejabberd_auth_pam.erl: Likewise

SVN Revision: 1966
2009-03-04 18:34:02 +00:00
Christophe Romain e4db030f4e Allow node creation without configure item
SVN Revision: 1962
2009-03-04 01:10:44 +00:00
Christophe Romain abbfa96fc4 backport typo fix from trunk
SVN Revision: 1959
2009-03-04 00:01:19 +00:00
Christophe Romain 55942d1f4a Add roster subscriptions handling and make PEP events sent to all resources
SVN Revision: 1957
2009-03-03 22:42:52 +00:00
Badlop 06abf6331b Merge fix from trunk r1910
* src/web/ejabberd_http.erl: Added a workaround for inet:peername
returning 'ebadf'

SVN Revision: 1928
2009-02-27 16:19:19 +00:00
Badlop 8be6b8df76 Merge fix from trunk r1190
* src/cyrsasl_digest.erl: Unquote backslash in DIGEST-MD5 quoted
strings (EJAB-304)

SVN Revision: 1927
2009-02-27 15:57:35 +00:00
Badlop a1e7e737bf * src/tls/tls_drv.c: S2S connection with STARTTLS fails to Gtalk
and recent Openfire (thanks to Philipp Hancke)(EJAB-877)

SVN Revision: 1926
2009-02-27 15:42:27 +00:00
Badlop fa08801574 * doc/guide.tex: No mention to the release date in ejabberd Guide
or release notes. The date of an ejabberd release is determined by
the date of the corresponding release announcement.

SVN Revision: 1922
2009-02-26 23:10:28 +00:00
Christophe Romain dcb05c4061 Do not call mod_caps:clear_caps as it breaks PubSub/PEP (EJAB-854)
SVN Revision: 1911
2009-02-23 15:51:01 +00:00
Badlop 6ea29663a3 Merge r1880 from trunk:
* src/mod_muc/mod_muc_room.erl: Owner of a password protected room
must provide the password, like other participants (EJAB-867)

SVN Revision: 1906
2009-02-21 09:37:05 +00:00
Badlop ad48607327 Merge r1879 from trunk:
* src/mod_muc/mod_muc_log.erl: Prevent XSS in MUC logs by
linkifying only a few known protocols (EJAB-850)

SVN Revision: 1905
2009-02-21 09:30:23 +00:00
Badlop fea7eac245 Merge r1877 from trunk:
* src/mod_roster.erl: When account is deleted, cancel presence
subscription for all roster items (EJAB-790)
* src/mod_roster_odbc.erl: Likewise

SVN Revision: 1904
2009-02-21 09:28:58 +00:00
Badlop b1f3d56beb Merge r1874 from trunk:
* src/mod_shared_roster.erl: Fix bug: a pending subscription
request, and later the requester added to the roster due to a
shared roster group, that request could neither be accepted or
rejected (thanks to Brian Cully)(EJAB-869)

SVN Revision: 1903
2009-02-21 09:27:27 +00:00
Badlop 7c6ccbb744 Merge r1864 from trunk:
* src/mod_pubsub/mod_pubsub.erl: The table pubsub_node in ejabberd
older than 2.0.2 had indexes for parentid and type. This is not
required since ejabberd 2.0.2, so those indexes can be
deleted. (EJAB-669)

SVN Revision: 1902
2009-02-21 09:26:12 +00:00
Badlop 02d7d0aa4c Merge r1862 from trunk:
* doc/Makefile: In Clean do not remove html. In new Distclean, remove also html.

SVN Revision: 1901
2009-02-21 09:24:57 +00:00
Badlop 7b10b69031 Merge r1861 from trunk:
* doc/Makefile: When cleaning, remove contributed_modules.tex

SVN Revision: 1900
2009-02-21 09:23:42 +00:00
Badlop 606b1d1b52 Merge r1858 from trunk:
* doc/guide.tex: Provide only an example of language option
* doc/guide.html: Likewise

SVN Revision: 1899
2009-02-21 09:22:51 +00:00
Badlop 2cd587bec5 Merge r1854 from trunk:
* doc/guide.tex: mod_muc can run in several nodes of cluster
* doc/guide.html: Likewise

SVN Revision: 1898
2009-02-21 09:21:31 +00:00
Badlop f6ee802960 Merge r1850 from trunk:
* src/odbc/mysql.sql: Fix complain about comment syntax
* src/odbc/pg.sql: Likewise

SVN Revision: 1897
2009-02-21 09:19:56 +00:00
Badlop e6ecb38ed9 Merge r1836 from trunk:
* doc/guide.tex: Explain that account creation is only supported
by internal and odbc authentication methods
* doc/guide.html: Likewise

SVN Revision: 1896
2009-02-21 09:19:11 +00:00
Badlop cd29a77759 Merge r1822 and partial r1834 from trunk:
* src/mod_privacy.erl: Privacy list items must be processed in the
specified order (EJAB-848)
* src/mod_privacy_odbc.erl: Likewise

SVN Revision: 1895
2009-02-21 09:15:43 +00:00
Badlop 677387bc80 Merge r1666 from trunk:
* src/ejabberd_c2s.erl: Ensure unique ID in roster push (EJAB-721)
* src/mod_roster.erl: Likewise
* src/mod_roster_odbc.erl: Likewise
* src/mod_shared_roster.erl: Likewise

SVN Revision: 1894
2009-02-21 09:12:59 +00:00
Christophe Romain f362fe93ec fix nodetree plugin resolver
SVN Revision: 1888
2009-02-19 11:24:26 +00:00
Christophe Romain 9b6343faa4 prevent from calling get_vh_registered_users/2 when not available
SVN Revision: 1870
2009-02-13 13:30:20 +00:00
41 changed files with 1006 additions and 413 deletions
+177
View File
@@ -1,3 +1,180 @@
2009-04-01 Badlop <badlop@process-one.net>
* doc/release_notes_2.0.5.txt: Added file for new release
2009-03-25 Badlop <badlop@process-one.net>
* src/expat_erl.c: Fix implicit declaration of function
x_fix_buff (thanks to Dennis Schridde)(EJAB-900)
2009-03-24 Badlop <badlop@process-one.net>
* src/ejabberd_sm.erl: Partially retract SVN r1976
EJAB-300 (EJAB-890). Check default privacy list when account, not
a specific session, receives a presence subscription
stanza (EJAB-300).
* src/ejabberd_c2s.erl: Likewise
2009-03-10 Badlop <badlop@process-one.net>
* doc/release_notes_2.0.4.txt: Added file for new release
* src/tls/tls_drv.c: Fix encryption problem for ejabberd_http
after timeout (thanks to Alexey Shchepin)(EJAB-880)
2009-03-10 Christophe Romain <christophe.romain@process-one.net>
* src/mod_pubsub/mod_pubsub.erl: Fix PEP with other domains and s2s
(EJAB-825). Also fixes send last published items in subscription.
2009-03-09 Badlop <badlop@process-one.net>
* src/tls/tls_drv.c: Fix to support OpenSSL older than
0.9.8f (EJAB-877)(thanks to Jonathan Schleifer)
* doc/guide.tex: It is again supported OpenSSL older than 0.9.8f
* doc/guide.html: Likewise
* src/mod_proxy65/mod_proxy65_service.erl: if an ip option is not
defined, the module takes an IP address of a local
hostname (thanks to Evgeniy Khramtsov)
2009-03-07 Badlop <badlop@process-one.net>
* src/ejabberd_c2s.erl: Enforce privacy rules also for
subscription requests (EJAB-300)
* src/ejabberd_sm.erl: Likewise
2009-03-06 Badlop <badlop@process-one.net>
* src/eldap/eldap.erl: moves waiting for response queries to
pending queue on an LDAP connection failure (thanks to Evgeniy
Khramtsov)
* src/eldap/eldap.erl: implemented queue for pending
queries (thanks to Evgeniy Khramtsov)
* src/eldap/eldap.erl: Close a connection on tcp_error (thanks to
Evgeniy Khramtsov)
* src/eldap/Makefile.in: added +optimize and +driver compilation
options (thanks to Evgeniy Khramtsov)
* src/eldap/Makefile.win32: Likewise
2009-03-05 Badlop <badlop@process-one.net>
* src/ejabberd_app.erl: In a Windows machine, explicitly add the
nameservers, as it seems Erlang does not do itself (EJAB-860)
* src/win32_dns.erl: Get name servers from Windows registy (thanks
to Geoff Cant)
* doc/guide.tex: Require OpenSSL 0.9.8f or higher (EJAB-877)
* doc/guide.html: Likewise
2009-03-04 Badlop <badlop@process-one.net>
* src/ejabberd_auth.erl: If anonymous auth is enabled, when
checking if the account already exists in other auth methods, take
into account if the auth method failed (EJAB-882)
* src/ejabberd_auth_anonymous.erl: Likewise
* src/ejabberd_auth_external.erl: Likewise
* src/ejabberd_auth_internal.erl: Likewise
* src/ejabberd_auth_ldap.erl: Likewise
* src/ejabberd_auth_odbc.erl: Likewise
* src/ejabberd_auth_pam.erl: Likewise
2009-03-04 Christophe Romain <christophe.romain@process-one.net>
* src/mod_pubsub/mod_pubsub.erl: Allow node creation without configure
item
2009-03-03 Christophe Romain <christophe.romain@process-one.net>
* src/mod_pubsub/mod_pubsub.erl: Add roster subscriptions handling
so on_sub_and_presence if fully supported.
* src/mod_pubsub/mod_pubsub.erl: Allow to send PEP events to all
connected ressources, even via s2s.
* src/mod_caps.erl: Likewise
2009-02-27 Badlop <badlop@process-one.net>
* src/web/ejabberd_http.erl: Added a workaround for inet:peername
returning 'ebadf'
* src/cyrsasl_digest.erl: Unquote backslash in DIGEST-MD5 quoted
strings (EJAB-304)
* src/tls/tls_drv.c: S2S connection with STARTTLS fails to Gtalk
and recent Openfire (thanks to Philipp Hancke)(EJAB-877)
* doc/guide.tex: No mention to the release date in ejabberd Guide
or release notes. The date of an ejabberd release is determined by
the date of the corresponding release announcement.
2009-02-23 Christophe Romain <christophe.romain@process-one.net>
* src/ejabberd_c2s.erl: Do not call mod_caps:clear_caps, this previous
optimization is too agressive and breaks PubSub/PEP standard behavior
(EJAB-854)
2009-02-21 Badlop <badlop@process-one.net>
* src/mod_muc/mod_muc_room.erl: Owner of a password protected room
must provide the password, like other participants (EJAB-867)
* src/mod_muc/mod_muc_log.erl: Prevent XSS in MUC logs by
linkifying only a few known protocols (EJAB-850)
* src/mod_roster.erl: When account is deleted, cancel presence
subscription for all roster items (EJAB-790)
* src/mod_roster_odbc.erl: Likewise
* src/mod_shared_roster.erl: Fix bug: a pending subscription
request, and later the requester added to the roster due to a
shared roster group, that request could neither be accepted or
rejected (thanks to Brian Cully)(EJAB-869)
* src/mod_pubsub/mod_pubsub.erl: The table pubsub_node in ejabberd
older than 2.0.2 had indexes for parentid and type. This is not
required since ejabberd 2.0.2, so those indexes can be
deleted. (EJAB-669)
* doc/Makefile: In Clean do not remove html. In new Distclean,
remove also html.
* doc/Makefile: When cleaning, remove contributed_modules.tex
* doc/guide.tex: Provide only an example of language option
* doc/guide.html: Likewise
* doc/guide.tex: mod_muc can run in several nodes of cluster
* doc/guide.html: Likewise
* src/odbc/mysql.sql: Fix complain about comment syntax
* src/odbc/pg.sql: Likewise
* doc/guide.tex: Explain that account creation is only supported
by internal and odbc authentication methods
* doc/guide.html: Likewise
* src/mod_privacy.erl: Privacy list items must be processed in the
specified order (EJAB-848)
* src/mod_privacy_odbc.erl: Likewise
* src/ejabberd_c2s.erl: Ensure unique ID in roster push (EJAB-721)
* src/mod_roster.erl: Likewise
* src/mod_roster_odbc.erl: Likewise
* src/mod_shared_roster.erl: Likewise
2009-02-19 Christophe Romain <christophe.romain@process-one.net>
* src/mod_pubsub/mod_pubsub.erl: fix nodetree plugin resolver
2009-02-13 Christophe Romain <christophe.romain@process-one.net>
* src/ejabberd_auth.erl: prevent from calling
get_vh_registered_users/2 when not available
2009-01-13 Badlop <badlop@process-one.net>
* doc/release_notes_2.0.3.txt: Minor changes
+2 -2
View File
@@ -1,5 +1,5 @@
% List of ejabberd-modules to add for ejabberd packaging (source archive and installer)
%
% HTTP-binding:
https://svn.process-one.net/ejabberd-modules/http_bind/branches/ejabberd-2.0.x
https://svn.process-one.net/ejabberd-modules/mod_http_fileserver/branches/ejabberd-2.0.x
https://svn.process-one.net/ejabberd-modules/http_bind/tags/ejabberd-2.0.5
https://svn.process-one.net/ejabberd-modules/mod_http_fileserver/tags/ejabberd-2.0.4
+4 -1
View File
@@ -32,7 +32,6 @@ pdf: guide.pdf features.pdf
clean:
rm -f *.aux
rm -f *.haux
rm -f *.html
rm -f *.htoc
rm -f *.idx
rm -f *.ilg
@@ -41,6 +40,10 @@ clean:
rm -f *.out
rm -f *.pdf
rm -f *.toc
[ ! -f contributed_modules.tex ] || rm contributed_modules.tex
distclean: clean
rm -f *.html
guide.html: guide.tex
hevea -fix -pedantic guide.tex
+2 -2
View File
@@ -2,7 +2,7 @@
"http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML>
<HEAD>
<TITLE>Ejabberd 2.0.x Developers Guide
<TITLE>Ejabberd 2.0.5 Developers Guide
</TITLE>
<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
@@ -49,7 +49,7 @@ TD P{margin:0px;}
<!--HEVEA command line is: /usr/bin/hevea -fix -pedantic dev.tex -->
<!--CUT DEF section 1 --><P><A NAME="titlepage"></A>
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.0.x Developers Guide</H1><H3 CLASS="titlerest">Alexey Shchepin<BR>
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.0.5 Developers Guide</H1><H3 CLASS="titlerest">Alexey Shchepin<BR>
<A HREF="mailto:alexey@sevcom.net"><TT>mailto:alexey@sevcom.net</TT></A><BR>
<A HREF="xmpp:aleksey@jabber.ru"><TT>xmpp:aleksey@jabber.ru</TT></A></H3></TD></TR>
</TABLE><DIV CLASS="center">
+2 -2
View File
@@ -2,7 +2,7 @@
"http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML>
<HEAD>
<TITLE>Ejabberd 2.0.x Feature Sheet
<TITLE>Ejabberd 2.0.5 Feature Sheet
</TITLE>
<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
@@ -50,7 +50,7 @@ SPAN{width:20%; float:right; text-align:left; margin-left:auto;}
<!--HEVEA command line is: /usr/bin/hevea -fix -pedantic features.tex -->
<!--CUT DEF section 1 --><P><A NAME="titlepage"></A>
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.0.x Feature Sheet</H1><H3 CLASS="titlerest">Sander Devrieze<BR>
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.0.5 Feature Sheet</H1><H3 CLASS="titlerest">Sander Devrieze<BR>
<A HREF="mailto:s.devrieze@pandora.be"><TT>mailto:s.devrieze@pandora.be</TT></A><BR>
<A HREF="xmpp:sander@devrieze.dyndns.org"><TT>xmpp:sander@devrieze.dyndns.org</TT></A></H3></TD></TR>
</TABLE><DIV CLASS="center">
+17 -21
View File
@@ -6,7 +6,7 @@
ejabberd 2.0.x
ejabberd 2.0.5
Installation and Operation Guide
@@ -76,7 +76,7 @@ BLOCKQUOTE.figure DIV.center DIV.center HR{display:none;}
<HR SIZE=2><BR>
<BR>
<TABLE CELLSPACING=6 CELLPADDING=0><TR><TD ALIGN=right NOWRAP> <FONT SIZE=6><B>ejabberd 2.0.x </B></FONT></TD></TR>
<TABLE CELLSPACING=6 CELLPADDING=0><TR><TD ALIGN=right NOWRAP> <FONT SIZE=6><B>ejabberd 2.0.5 </B></FONT></TD></TR>
<TR><TD ALIGN=right NOWRAP>&nbsp;</TD></TR>
<TR><TD ALIGN=right NOWRAP> <FONT SIZE=6>Installation and Operation Guide</FONT></TD></TR>
</TABLE><BR>
@@ -457,7 +457,7 @@ variable.
</P></LI><LI CLASS="li-enumerate">Install OpenSSL in <CODE>C:\sdk\OpenSSL</CODE> and add <CODE>C:\sdk\OpenSSL\lib\VC</CODE> to your path or copy the binaries to your system directory.
</LI><LI CLASS="li-enumerate">Install ZLib in <CODE>C:\sdk\gnuWin32</CODE>. Copy
<CODE>C:\sdk\GnuWin32\bin\zlib1.dll</CODE> to your system directory. If you change your path it should already be set after libiconv install.
</LI><LI CLASS="li-enumerate">Make sure the you can access Erlang binaries from your path. For example: <CODE>set PATH=%PATH%;"C:\sdk\erl5.5.5\bin"</CODE>
</LI><LI CLASS="li-enumerate">Make sure the you can access Erlang binaries from your path. For example: <CODE>set PATH=%PATH%;"C:\sdk\erl5.6.5\bin"</CODE>
</LI><LI CLASS="li-enumerate">Depending on how you end up actually installing the library you might need to check and tweak the paths in the file configure.erl.
</LI><LI CLASS="li-enumerate">While in the directory <CODE>ejabberd\src</CODE> run:
<PRE CLASS="verbatim">configure.bat
@@ -892,7 +892,7 @@ example authentication scripts</A>.
<A HREF="#mssql">3.2.2</A> and <A HREF="#odbc">3.2.4</A>.
</LI><LI CLASS="li-itemize">anonymous &#X2014; See section&#XA0;<A HREF="#saslanonymous">3.1.4</A>.
</LI><LI CLASS="li-itemize">pam &#X2014; See section&#XA0;<A HREF="#pam">3.1.4</A>.
</LI></UL><P> <A NAME="internalauth"></A> </P><!--TOC subsubsection Internal-->
</LI></UL><P>Account creation is only supported by internal and odbc methods.</P><P> <A NAME="internalauth"></A> </P><!--TOC subsubsection Internal-->
<H4 CLASS="subsubsection"><!--SEC ANCHOR --><A HREF="#internalauth">Internal</A></H4><!--SEC END --><P> <A NAME="internalauth"></A>
</P><P><TT>ejabberd</TT> uses its internal Mnesia database as the default authentication method.</P><UL CLASS="itemize"><LI CLASS="li-itemize">
<TT>auth_method</TT>: The value <TT>internal</TT> will enable the internal
@@ -1119,13 +1119,9 @@ To define a shaper named &#X2018;<TT>normal</TT>&#X2019; with traffic speed limi
can be seen by Jabber clients. If a Jabber client do not support
<TT>xml:lang</TT>, the specified language is used. The default value is
<TT>en</TT>. In order to take effect there must be a translation file
<TT>&lt;language&gt;.msg</TT> in <TT>ejabberd</TT>&#X2019;s <TT>msgs</TT> directory.</P><P>Examples:
</P><UL CLASS="itemize"><LI CLASS="li-itemize">
To set Russian as default language:
<PRE CLASS="verbatim">{language, "ru"}.
</PRE></LI><LI CLASS="li-itemize">To set Spanish as default language:
<PRE CLASS="verbatim">{language, "es"}.
</PRE></LI></UL><P> <A NAME="database"></A> </P><!--TOC section Database and LDAP Configuration-->
<TT>&lt;language&gt;.msg</TT> in <TT>ejabberd</TT>&#X2019;s <TT>msgs</TT> directory.</P><P>For example, to set Russian as default language:
</P><PRE CLASS="verbatim">{language, "ru"}.
</PRE><P> <A NAME="database"></A> </P><!--TOC section Database and LDAP Configuration-->
<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc28">3.2</A>&#XA0;&#XA0;<A HREF="#database">Database and LDAP Configuration</A></H2><!--SEC END --><P> <A NAME="database"></A>
</P><P><TT>ejabberd</TT> uses its internal Mnesia database by default. However, it is
@@ -1152,7 +1148,7 @@ if you define several domains in ejabberd.cfg (see section <A HREF="#hostnames">
you probably want that each virtual host uses a different configuration of database, authentication and storage,
so that usernames do not conflict and mix between different virtual hosts.
For that purpose, the options described in the next sections
must be set inside a <TT>host_cofig</TT> for each vhost (see section <A HREF="#virtualhost">3.1.2</A>).
must be set inside a <TT>host_config</TT> for each vhost (see section <A HREF="#virtualhost">3.1.2</A>).
For example:
</P><PRE CLASS="verbatim">{host_config, "public.example.org", [
{odbc_server, {pgsql, "localhost", "database-public-example-org", "ejabberd", "password"}},
@@ -2344,7 +2340,7 @@ In the body you can set a newline with the characters: <CODE>\n</CODE>
list of JIDs which will be notified each time a new account is registered.
</DD><DT CLASS="dt-description"><B><TT>iqdisc</TT></B></DT><DD CLASS="dd-description"> This specifies
the processing discipline for In-Band Registration (<TT>jabber:iq:register</TT>) IQ queries (see section&#XA0;<A HREF="#modiqdiscoption">3.3.2</A>).
</DD></DL><P>This module reads also another option defined globably for the server:
</DD></DL><P>This module reads also another option defined globally for the server:
<TT>{registration_timeout, Timeout}</TT>.
This option limits the frequency of registration from a given IP or username.
So, a user can&#X2019;t register a new account from the same IP address or JID during
@@ -2809,7 +2805,7 @@ they are automatically renamed to <TT>"*-old.log"</TT>. See section <A HREF="#lo
Store internal Mnesia database to a binary backup file.
</DD><DT CLASS="dt-description"><B><TT>restore ejabberd.backup</TT></B></DT><DD CLASS="dd-description">
Restore immediately from a binary backup file the internal Mnesia database.
This will comsume quite some memory for big servers.
This will consume quite some memory for big servers.
</DD><DT CLASS="dt-description"><B><TT>install-fallback ejabberd.backup</TT></B></DT><DD CLASS="dd-description">
The binary backup file is installed as fallback:
it will be used to restore the database at the next ejabberd start.
@@ -2831,9 +2827,9 @@ This allows to administer a remote node.</P><P>The <TT>ejabberdctl</TT> script c
This file includes detailed information about each configurable option.</P><P>The <TT>ejabberdctl</TT> script returns a numerical status code.
Success is represented by <TT>0</TT>,
error is represented by <TT>1</TT>,
and other codes may be used for specifical results.
and other codes may be used for specific results.
This can be used by other scripts to determine automatically
if a command succedded or failed,
if a command succeeded or failed,
for example using: <TT>echo $?</TT></P><P> <A NAME="erlangconfiguration"></A> </P><!--TOC subsection Erlang Runtime System-->
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc61">4.1.2</A>&#XA0;&#XA0;<A HREF="#erlangconfiguration">Erlang Runtime System</A></H3><!--SEC END --><P> <A NAME="erlangconfiguration"></A> </P><P><TT>ejabberd</TT> is an Erlang/OTP application that runs inside an Erlang runtime system.
This system is configured using environment variables and command line parameters.
@@ -3128,11 +3124,11 @@ Writing, on the other hand, will be slower. And of course if machine with one
of the replicas is down, other replicas will be used.</P><P>Also <A HREF="http://www.erlang.org/doc/apps/mnesia/Mnesia_chap5.html#5.3">section 5.3 (Table Fragmentation) of Mnesia User&#X2019;s Guide</A> can be helpful.
</P><P>(alt) Same as in previous item, but for other tables.</P></LI><LI CLASS="li-enumerate">Run &#X2018;<CODE>init:stop().</CODE>&#X2019; or just &#X2018;<CODE>q().</CODE>&#X2019; to exit from
the Erlang shell. This probably can take some time if Mnesia has not yet
transfered and processed all data it needed from <TT>first</TT>.</LI><LI CLASS="li-enumerate">Now run <TT>ejabberd</TT> on <TT>second</TT> with almost the same config as
on <TT>first</TT> (you probably do not need to duplicate &#X2018;<CODE>acl</CODE>&#X2019;
and &#X2018;<CODE>access</CODE>&#X2019; options &#X2014; they will be taken from
<TT>first</TT>, and <CODE>mod_muc</CODE> and <CODE>mod_irc</CODE> should be
enabled only on one machine in the cluster).
transfered and processed all data it needed from <TT>first</TT>.</LI><LI CLASS="li-enumerate">Now run <TT>ejabberd</TT> on <TT>second</TT> with a configuration similar as
on <TT>first</TT>: you probably do not need to duplicate &#X2018;<CODE>acl</CODE>&#X2019;
and &#X2018;<CODE>access</CODE>&#X2019; options because they will be taken from
<TT>first</TT>; and <CODE>mod_irc</CODE> should be
enabled only on one machine in the cluster.
</LI></OL><P>You can repeat these steps for other machines supposed to serve this
domain.</P><P> <A NAME="servicelb"></A> </P><!--TOC section Service Load-Balancing-->
<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc78">6.3</A>&#XA0;&#XA0;<A HREF="#servicelb">Service Load-Balancing</A></H2><!--SEC END --><P> <A NAME="servicelb"></A>
+13 -21
View File
@@ -126,9 +126,6 @@ the processing discipline for #1 IQ queries (see section~\ref{modiqdiscoption}).
{\rule{\larg}{1mm}}
\begin{latexonly}
\vspace{2mm} \\
\begin{center}
{\large \bf \today}
\end{center}
\vspace{5.5cm}
\end{latexonly}
}
@@ -1035,6 +1032,8 @@ The following authentication methods are supported by \ejabberd{}:
\item pam --- See section~\ref{pam}.
\end{itemize}
Account creation is only supported by internal and odbc methods.
\makesubsubsection{internalauth}{Internal}
\ind{internal authentication}\ind{Mnesia}
@@ -1387,17 +1386,10 @@ can be seen by \Jabber{} clients. If a \Jabber{} client do not support
\term{en}. In order to take effect there must be a translation file
\term{<language>.msg} in \ejabberd{}'s \term{msgs} directory.
Examples:
\begin{itemize}
\item To set Russian as default language:
For example, to set Russian as default language:
\begin{verbatim}
{language, "ru"}.
\end{verbatim}
\item To set Spanish as default language:
\begin{verbatim}
{language, "es"}.
\end{verbatim}
\end{itemize}
\makesection{database}{Database and LDAP Configuration}
\ind{database}
@@ -1433,7 +1425,7 @@ if you define several domains in ejabberd.cfg (see section \ref{hostnames}),
you probably want that each virtual host uses a different configuration of database, authentication and storage,
so that usernames do not conflict and mix between different virtual hosts.
For that purpose, the options described in the next sections
must be set inside a \term{host\_cofig} for each vhost (see section \ref{virtualhost}).
must be set inside a \term{host\_config} for each vhost (see section \ref{virtualhost}).
For example:
\begin{verbatim}
{host_config, "public.example.org", [
@@ -2994,7 +2986,7 @@ Options:
\iqdiscitem{In-Band Registration (\ns{jabber:iq:register})}
\end{description}
This module reads also another option defined globably for the server:
This module reads also another option defined globally for the server:
\term{\{registration\_timeout, Timeout\}}. \ind{options!registratimeout}
This option limits the frequency of registration from a given IP or username.
So, a user can't register a new account from the same IP address or JID during
@@ -3584,7 +3576,7 @@ The more interesting ones are:
Store internal Mnesia database to a binary backup file.
\titem {restore ejabberd.backup}
Restore immediately from a binary backup file the internal Mnesia database.
This will comsume quite some memory for big servers.
This will consume quite some memory for big servers.
\titem {install-fallback ejabberd.backup}
The binary backup file is installed as fallback:
it will be used to restore the database at the next ejabberd start.
@@ -3614,9 +3606,9 @@ This file includes detailed information about each configurable option.
The \term{ejabberdctl} script returns a numerical status code.
Success is represented by \term{0},
error is represented by \term{1},
and other codes may be used for specifical results.
and other codes may be used for specific results.
This can be used by other scripts to determine automatically
if a command succedded or failed,
if a command succeeded or failed,
for example using: \term{echo \$?}
@@ -4048,11 +4040,11 @@ mnesia:change_table_copy_type(schema, node(), disc_copies).
transfered and processed all data it needed from \term{first}.
\item Now run \ejabberd{} on \term{second} with almost the same config as
on \term{first} (you probably do not need to duplicate `\verb|acl|'
and `\verb|access|' options --- they will be taken from
\term{first}, and \verb|mod_muc| and \verb|mod_irc| should be
enabled only on one machine in the cluster).
\item Now run \ejabberd{} on \term{second} with a configuration similar as
on \term{first}: you probably do not need to duplicate `\verb|acl|'
and `\verb|access|' options because they will be taken from
\term{first}; and \verb|mod_irc| should be
enabled only on one machine in the cluster.
\end{enumerate}
You can repeat these steps for other machines supposed to serve this
+44
View File
@@ -0,0 +1,44 @@
Release Notes
ejabberd 2.0.4
ejabberd 2.0.4 is the fourth bugfix release for ejabberd 2.0.x branch.
ejabberd 2.0.4 includes several bugfixes.
A detailed list of changes can be retrieved from:
http://redir.process-one.net/ejabberd-2.0.4
The new code can be downloaded from ejabberd download page:
http://www.process-one.net/en/ejabberd/
The changes are:
- Ensure ID attribute in roster push is unique
- Authentication: Fix Anonymous auth when enabled with broken ODBC
- Authentication: Unquote correctly backslash in DIGEST-MD5 SASL responses
- Authentication: Cancel presence subscriptions on account deletion
- LDAP: Close a connection on tcp_error
- LDAP: Implemented queue for pending queries
- LDAP: On failure of LDAP connection, waiting is done on pending queue
- MUC: Owner of a password protected room must also provide the password
- MUC: Prevent XSS in MUC logs by linkifying only a few known protocols
- Privacy rules: Items are now processed in the specified order
- Privacy rules: Fix to correctly block subscription requests
- Proxy65: If ip option is not defined, take an IP address of a local hostname
- PubSub: Add roster subscription handling; send PEP events to all resources
- PubSub: Allow node creation without configure item
- PubSub: Requesting items on a node which exists, but empty returns an error
- PEP: Fix sending notifications to other domains and s2s
- S2S: Fix problem with encrypted connection to Gtalk and recent Openfire
- S2S: Workaround to get DNS SRV lookup to work on Windows machine
- Shared Roster Groups: Fix to not resend authorization request
- WebAdmin: Fix encryption problem for ejabberd_http after timeout
Bug reports
You can officially report bugs on ProcessOne support site:
http://support.process-one.net/
END
+33
View File
@@ -0,0 +1,33 @@
Release Notes
ejabberd 2.0.5
ejabberd 2.0.5 is the fifth bugfix release in ejabberd 2.0.x branch.
ejabberd 2.0.5 includes three bugfixes.
More details of those fixes can be retrieved from:
http://redir.process-one.net/ejabberd-2.0.5
The new code can be downloaded from ejabberd download page:
http://www.process-one.net/en/ejabberd/
The changes are:
- Fix two problems introduced in ejabberd 2.0.4: subscription request
produced many authorization requests with some clients and
transports; and subscription requests were not stored for later
delivery when receiver was offline.
- Fix warning in expat_erl.c about implicit declaration of x_fix_buff
- HTTP-Bind (BOSH): Fix a missing stream:error in the returned
remote-stream-error stanza
Bug reports
You can officially report bugs on ProcessOne support site:
http://support.process-one.net/
END
+1 -1
View File
@@ -1,2 +1,2 @@
% ejabberd version (automatically generated).
\newcommand{\version}{2.0.x}
\newcommand{\version}{2.0.5}
+4 -2
View File
@@ -101,15 +101,17 @@ parse1([], [], T) ->
parse1([], _S, _T) ->
bad.
parse2([$" | Cs], Key, Val, Ts) ->
parse2([$\" | Cs], Key, Val, Ts) ->
parse3(Cs, Key, Val, Ts);
parse2([C | Cs], Key, Val, Ts) ->
parse4(Cs, Key, [C | Val], Ts);
parse2([], _, _, _) ->
bad.
parse3([$" | Cs], Key, Val, Ts) ->
parse3([$\" | Cs], Key, Val, Ts) ->
parse4(Cs, Key, Val, Ts);
parse3([$\\, C | Cs], Key, Val, Ts) ->
parse3(Cs, Key, [C | Val], Ts);
parse3([C | Cs], Key, Val, Ts) ->
parse3(Cs, Key, [C | Val], Ts);
parse3([], _, _, _) ->
+1 -1
View File
@@ -2,7 +2,7 @@
{application, ejabberd,
[{description, "ejabberd"},
{vsn, "2.0.x"},
{vsn, "2.0.5"},
{modules, [acl,
adhoc,
configure,
+13
View File
@@ -62,6 +62,7 @@ start(normal, _Args) ->
%eprof:start(),
%eprof:profile([self()]),
%fprof:trace(start, "/tmp/fprof"),
maybe_add_nameservers(),
start_modules(),
Sup;
start(_, _) ->
@@ -168,3 +169,15 @@ connect_nodes() ->
end, Nodes)
end.
%% If ejabberd is running on some Windows machine, get nameservers and add to Erlang
maybe_add_nameservers() ->
case os:type() of
{win32, _} -> add_windows_nameservers();
_ -> ok
end.
add_windows_nameservers() ->
IPTs = win32_dns:get_nameservers(),
?INFO_MSG("Adding machine's DNS IPs to Erlang system:~n~p", [IPTs]),
lists:foreach(fun(IPT) -> inet_db:add_ns(IPT) end, IPTs).
+48 -30
View File
@@ -80,20 +80,21 @@ plain_password_required(Server) ->
%% @spec (User::string(), Server::string(), Password::string()) ->
%% true | false
check_password(User, Server, Password) ->
lists:any(
fun(M) ->
M:check_password(User, Server, Password)
end, auth_modules(Server)).
case check_password_with_authmodule(User, Server, Password) of
{true, _AuthModule} -> true;
false -> false
end.
%% @doc Check if the user and password can login in server.
%% @spec (User::string(), Server::string(), Password::string(),
%% StreamID::string(), Digest::string()) ->
%% true | false
check_password(User, Server, Password, StreamID, Digest) ->
lists:any(
fun(M) ->
M:check_password(User, Server, Password, StreamID, Digest)
end, auth_modules(Server)).
case check_password_with_authmodule(User, Server, Password,
StreamID, Digest) of
{true, _AuthModule} -> true;
false -> false
end.
%% @doc Check if the user and password can login in server.
%% The user can login if at least an authentication method accepts the user
@@ -106,27 +107,23 @@ check_password(User, Server, Password, StreamID, Digest) ->
%% | ejabberd_auth_internal | ejabberd_auth_ldap
%% | ejabberd_auth_odbc | ejabberd_auth_pam
check_password_with_authmodule(User, Server, Password) ->
Res = lists:dropwhile(
fun(M) ->
not apply(M, check_password,
[User, Server, Password])
end, auth_modules(Server)),
case Res of
[] -> false;
[AuthMod | _] -> {true, AuthMod}
end.
check_password_loop(auth_modules(Server), [User, Server, Password]).
check_password_with_authmodule(User, Server, Password, StreamID, Digest) ->
Res = lists:dropwhile(
fun(M) ->
not apply(M, check_password,
[User, Server, Password, StreamID, Digest])
end, auth_modules(Server)),
case Res of
[] -> false;
[AuthMod | _] -> {true, AuthMod}
check_password_loop(auth_modules(Server), [User, Server, Password,
StreamID, Digest]).
check_password_loop([], _Args) ->
false;
check_password_loop([AuthModule | AuthModules], Args) ->
case apply(AuthModule, check_password, Args) of
true ->
{true, AuthModule};
false ->
check_password_loop(AuthModules, Args)
end.
%% @spec (User::string(), Server::string(), Password::string()) ->
%% ok | {error, ErrorType}
%% where ErrorType = empty_password | not_allowed | invalid_jid
@@ -187,7 +184,13 @@ get_vh_registered_users(Server) ->
get_vh_registered_users(Server, Opts) ->
lists:flatmap(
fun(M) ->
M:get_vh_registered_users(Server, Opts)
case erlang:function_exported(
M, get_vh_registered_users, 2) of
true ->
M:get_vh_registered_users(Server, Opts);
false ->
M:get_vh_registered_users(Server)
end
end, auth_modules(Server)).
get_vh_registered_users_number(Server) ->
@@ -255,11 +258,26 @@ is_user_exists(User, Server) ->
%% Check if the user exists in all authentications module except the module
%% passed as parameter
%% @spec (Module::atom(), User, Server) -> true | false | maybe
is_user_exists_in_other_modules(Module, User, Server) ->
lists:any(
fun(M) ->
M:is_user_exists(User, Server)
end, auth_modules(Server)--[Module]).
is_user_exists_in_other_modules_loop(
auth_modules(Server)--[Module],
User, Server).
is_user_exists_in_other_modules_loop([], _User, _Server) ->
false;
is_user_exists_in_other_modules_loop([AuthModule|AuthModules], User, Server) ->
case AuthModule:is_user_exists(User, Server) of
true ->
true;
false ->
is_user_exists_in_other_modules_loop(AuthModules, User, Server);
{error, Error} ->
?DEBUG("The authentication module ~p returned an error~nwhen "
"checking user ~p in server ~p~nError message: ~p",
[AuthModule, User, Server, Error]),
maybe
end.
%% @spec (User, Server) -> ok | error | {error, not_allowed}
%% @doc Remove user.
+3
View File
@@ -178,7 +178,10 @@ check_password(User, Server, _Password, _StreamID, _Digest) ->
%% they however are "reserved")
case ejabberd_auth:is_user_exists_in_other_modules(?MODULE,
User, Server) of
%% If user exists in other module, reject anonnymous authentication
true -> false;
%% If we are not sure whether the user exists in other module, reject anon auth
maybe -> false;
false -> login(User, Server)
end.
+6 -1
View File
@@ -83,8 +83,13 @@ get_password(_User, _Server) ->
get_password_s(_User, _Server) ->
"".
%% @spec (User, Server) -> true | false | {error, Error}
is_user_exists(User, Server) ->
extauth:is_user_exists(User, Server).
try extauth:is_user_exists(User, Server) of
Res -> Res
catch
_:Error -> {error, Error}
end.
remove_user(_User, _Server) ->
{error, not_allowed}.
+3 -2
View File
@@ -230,6 +230,7 @@ get_password_s(User, Server) ->
[]
end.
%% @spec (User, Server) -> true | false | {error, Error}
is_user_exists(User, Server) ->
LUser = jlib:nodeprep(User),
LServer = jlib:nameprep(Server),
@@ -239,8 +240,8 @@ is_user_exists(User, Server) ->
false;
[_] ->
true;
_ ->
false
Other ->
{error, Other}
end.
%% @spec (User, Server) -> ok
+3 -2
View File
@@ -186,10 +186,11 @@ get_password(_User, _Server) ->
get_password_s(_User, _Server) ->
"".
%% @spec (User, Server) -> true | false | {error, Error}
is_user_exists(User, Server) ->
case catch is_user_exists_ldap(User, Server) of
{'EXIT', _} ->
false;
{'EXIT', Error} ->
{error, Error};
Result ->
Result
end.
+32 -11
View File
@@ -61,6 +61,7 @@ start(Host) ->
plain_password_required() ->
false.
%% @spec (User, Server, Password) -> true | false | {error, Error}
check_password(User, Server, Password) ->
case jlib:nodeprep(User) of
error ->
@@ -68,14 +69,22 @@ check_password(User, Server, Password) ->
LUser ->
Username = ejabberd_odbc:escape(LUser),
LServer = jlib:nameprep(Server),
case catch odbc_queries:get_password(LServer, Username) of
try odbc_queries:get_password(LServer, Username) of
{selected, ["password"], [{Password}]} ->
true;
_ ->
false
true; %% Password is correct
{selected, ["password"], [{_Password2}]} ->
false; %% Password is not correct
{selected, ["password"], []} ->
false; %% Account does not exist
{error, _Error} ->
false %% Typical error is that table doesn't exist
catch
_:_ ->
false %% Typical error is database not accessible
end
end.
%% @spec (User, Server, Password, StreamID, Digest) -> true | false | {error, Error}
check_password(User, Server, Password, StreamID, Digest) ->
case jlib:nodeprep(User) of
error ->
@@ -83,7 +92,8 @@ check_password(User, Server, Password, StreamID, Digest) ->
LUser ->
Username = ejabberd_odbc:escape(LUser),
LServer = jlib:nameprep(Server),
case catch odbc_queries:get_password(LServer, Username) of
try odbc_queries:get_password(LServer, Username) of
%% Account exists, check if password is valid
{selected, ["password"], [{Passwd}]} ->
DigRes = if
Digest /= "" ->
@@ -96,8 +106,13 @@ check_password(User, Server, Password, StreamID, Digest) ->
true ->
(Passwd == Password) and (Password /= "")
end;
_ ->
false
{selected, ["password"], []} ->
false; %% Account does not exist
{error, _Error} ->
false %% Typical error is that table doesn't exist
catch
_:_ ->
false %% Typical error is database not accessible
end
end.
@@ -208,6 +223,7 @@ get_password_s(User, Server) ->
end
end.
%% @spec (User, Server) -> true | false | {error, Error}
is_user_exists(User, Server) ->
case jlib:nodeprep(User) of
error ->
@@ -215,11 +231,16 @@ is_user_exists(User, Server) ->
LUser ->
Username = ejabberd_odbc:escape(LUser),
LServer = jlib:nameprep(Server),
case catch odbc_queries:get_password(LServer, Username) of
try odbc_queries:get_password(LServer, Username) of
{selected, ["password"], [{_Password}]} ->
true;
_ ->
false
true; %% Account exists
{selected, ["password"], []} ->
false; %% Account does not exist
{error, Error} ->
{error, Error} %% Typical error is that table doesn't exist
catch
_:B ->
{error, B} %% Typical error is database not accessible
end
end.
+2
View File
@@ -80,6 +80,8 @@ get_password(_User, _Server) ->
get_password_s(_User, _Server) ->
"".
%% @spec (User, Server) -> true | false | {error, Error}
%% TODO: Improve this function to return an error instead of 'false' when connection to PAM failed
is_user_exists(User, Host) ->
Service = get_pam_service(Host),
case catch epam:acct_mgmt(Service, User) of
+25 -6
View File
@@ -1091,13 +1091,17 @@ handle_info({route, From, To, Packet}, StateName, StateData) ->
Attrs1 = lists:keydelete("type", 1, Attrs),
{true, [{"type", "unavailable"} | Attrs1], StateData};
"subscribe" ->
{true, Attrs, StateData};
SRes = is_privacy_allow(From, To, Packet, StateData#state.privacy_list),
{SRes, Attrs, StateData};
"subscribed" ->
{true, Attrs, StateData};
SRes = is_privacy_allow(From, To, Packet, StateData#state.privacy_list),
{SRes, Attrs, StateData};
"unsubscribe" ->
{true, Attrs, StateData};
SRes = is_privacy_allow(From, To, Packet, StateData#state.privacy_list),
{SRes, Attrs, StateData};
"unsubscribed" ->
{true, Attrs, StateData};
SRes = is_privacy_allow(From, To, Packet, StateData#state.privacy_list),
{SRes, Attrs, StateData};
_ ->
case ejabberd_hooks:run_fold(
privacy_check_packet, StateData#state.server,
@@ -1113,7 +1117,9 @@ handle_info({route, From, To, Packet}, StateName, StateData) ->
%% Note contact availability
case xml:get_attr_s("type", Attrs) of
"unavailable" ->
mod_caps:clear_caps(From);
%mod_caps:clear_caps(From);
% caps clear disabled cause it breaks things
ok;
_ ->
Caps = mod_caps:read_caps(Els),
mod_caps:note_caps(StateData#state.server, From, Caps)
@@ -1171,7 +1177,7 @@ handle_info({route, From, To, Packet}, StateName, StateData) ->
NewPL ->
PrivPushIQ =
#iq{type = set, xmlns = ?NS_PRIVACY,
id = "push",
id = "push" ++ randoms:get_string(),
sub_el = [{xmlelement, "query",
[{"xmlns", ?NS_PRIVACY}],
[{xmlelement, "list",
@@ -1617,6 +1623,19 @@ presence_track(From, To, Packet, StateData) ->
pres_a = A}
end.
%% Check if privacy rules allow this delivery
is_privacy_allow(From, To, Packet, PrivacyList) ->
User = To#jid.user,
Server = To#jid.server,
allow == ejabberd_hooks:run_fold(
privacy_check_packet, Server,
allow,
[User,
Server,
PrivacyList,
{From, To, Packet},
in]).
presence_broadcast(StateData, From, JIDSet, Packet) ->
lists:foreach(fun(JID) ->
FJID = jlib:make_jid(JID),
+34 -4
View File
@@ -59,6 +59,7 @@
-include("ejabberd.hrl").
-include("jlib.hrl").
-include("ejabberd_ctl.hrl").
-include("mod_privacy.hrl").
-record(session, {sid, usr, us, priority, info}).
-record(state, {}).
@@ -384,28 +385,32 @@ do_route(From, To, Packet) ->
Reason = xml:get_path_s(
Packet,
[{elem, "status"}, cdata]),
{ejabberd_hooks:run_fold(
{is_privacy_allow(From, To, Packet) andalso
ejabberd_hooks:run_fold(
roster_in_subscription,
LServer,
false,
[User, Server, From, subscribe, Reason]),
true};
"subscribed" ->
{ejabberd_hooks:run_fold(
{is_privacy_allow(From, To, Packet) andalso
ejabberd_hooks:run_fold(
roster_in_subscription,
LServer,
false,
[User, Server, From, subscribed, ""]),
true};
"unsubscribe" ->
{ejabberd_hooks:run_fold(
{is_privacy_allow(From, To, Packet) andalso
ejabberd_hooks:run_fold(
roster_in_subscription,
LServer,
false,
[User, Server, From, unsubscribe, ""]),
true};
"unsubscribed" ->
{ejabberd_hooks:run_fold(
{is_privacy_allow(From, To, Packet) andalso
ejabberd_hooks:run_fold(
roster_in_subscription,
LServer,
false,
@@ -469,6 +474,31 @@ do_route(From, To, Packet) ->
end
end.
%% The default list applies to the user as a whole,
%% and is processed if there is no active list set
%% for the target session/resource to which a stanza is addressed,
%% or if there are no current sessions for the user.
is_privacy_allow(From, To, Packet) ->
User = To#jid.user,
Server = To#jid.server,
PrivacyList = ejabberd_hooks:run_fold(privacy_get_user_list, Server,
#userlist{}, [User, Server]),
is_privacy_allow(From, To, Packet, PrivacyList).
%% Check if privacy rules allow this delivery
%% Function copied from ejabberd_c2s.erl
is_privacy_allow(From, To, Packet, PrivacyList) ->
User = To#jid.user,
Server = To#jid.server,
allow == ejabberd_hooks:run_fold(
privacy_check_packet, Server,
allow,
[User,
Server,
PrivacyList,
{From, To, Packet},
in]).
route_message(From, To, Packet) ->
LUser = To#jid.luser,
LServer = To#jid.lserver,
+3 -1
View File
@@ -6,6 +6,8 @@ CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
ASN_FLAGS = -bber_bin +optimize +driver
ERLANG_CFLAGS = @ERLANG_CFLAGS@
ERLANG_LIBS = @ERLANG_LIBS@
@@ -25,7 +27,7 @@ all: $(BEAMS) ELDAPv3.beam
ELDAPv3.beam: ELDAPv3.erl
ELDAPv3.erl: ELDAPv3.asn
@ERLC@ -bber_bin -W $(EFLAGS) $<
@ERLC@ $(ASN_FLAGS) -W $(EFLAGS) $<
$(OUTDIR)/%.beam: %.erl ELDAPv3.erl
@ERLC@ -W $(EFLAGS) -o $(OUTDIR) $<
+3 -1
View File
@@ -6,6 +6,8 @@ EFLAGS = -I .. -pz ..
OUTDIR = ..
BEAMS = ..\eldap.beam ..\eldap_filter.beam ..\eldap_pool.beam ..\eldap_utils.beam
ASN_FLAGS = -bber_bin +optimize +driver
ALL : $(BEAMS)
Clean :
@@ -16,7 +18,7 @@ Clean :
-@erase $(BEAMS)
ELDAPv3.erl : ELDAPv3.asn
erlc -bber_bin -W $(EFLAGS) ELDAPv3.asn
erlc $(ASN_FLAGS) -W $(EFLAGS) ELDAPv3.asn
$(OUTDIR)\eldap.beam : eldap.erl ELDAPv3.erl
erlc -W $(EFLAGS) -o $(OUTDIR) eldap.erl
+116 -104
View File
@@ -85,6 +85,10 @@
-define(RETRY_TIMEOUT, 500).
-define(BIND_TIMEOUT, 10000).
-define(CMD_TIMEOUT, 100000).
%% Used in gen_fsm sync calls.
-define(CALL_TIMEOUT, ?CMD_TIMEOUT + ?BIND_TIMEOUT + ?RETRY_TIMEOUT).
%% Used as a timeout for gen_tcp:send/2
-define(SEND_TIMEOUT, 30000).
-define(MAX_TRANSACTION_ID, 65535).
-define(MIN_TRANSACTION_ID, 0).
@@ -98,7 +102,7 @@
id = 0, % LDAP Request ID
bind_timer, % Ref to bind timeout
dict, % dict holding operation params and results
bind_q % Queue for bind() requests
req_q % Queue for requests
}).
%%%----------------------------------------------------------------------
@@ -141,7 +145,8 @@ close(Handle) ->
%%% --------------------------------------------------------------------
add(Handle, Entry, Attributes) when list(Entry),list(Attributes) ->
Handle1 = get_handle(Handle),
gen_fsm:sync_send_event(Handle1, {add, Entry, add_attrs(Attributes)}).
gen_fsm:sync_send_event(Handle1, {add, Entry, add_attrs(Attributes)},
?CALL_TIMEOUT).
%%% Do sanity check !
add_attrs(Attrs) ->
@@ -166,7 +171,7 @@ add_attrs(Attrs) ->
%%% --------------------------------------------------------------------
delete(Handle, Entry) when list(Entry) ->
Handle1 = get_handle(Handle),
gen_fsm:sync_send_event(Handle1, {delete, Entry}).
gen_fsm:sync_send_event(Handle1, {delete, Entry}, ?CALL_TIMEOUT).
%%% --------------------------------------------------------------------
%%% Modify an entry. Given an entry a number of modification
@@ -181,7 +186,7 @@ delete(Handle, Entry) when list(Entry) ->
%%% --------------------------------------------------------------------
modify(Handle, Object, Mods) when list(Object), list(Mods) ->
Handle1 = get_handle(Handle),
gen_fsm:sync_send_event(Handle1, {modify, Object, Mods}).
gen_fsm:sync_send_event(Handle1, {modify, Object, Mods}, ?CALL_TIMEOUT).
%%%
%%% Modification operations.
@@ -214,7 +219,10 @@ m(Operation, Type, Values) ->
modify_dn(Handle, Entry, NewRDN, DelOldRDN, NewSup)
when list(Entry),list(NewRDN),atom(DelOldRDN),list(NewSup) ->
Handle1 = get_handle(Handle),
gen_fsm:sync_send_event(Handle1, {modify_dn, Entry, NewRDN, bool_p(DelOldRDN), optional(NewSup)}).
gen_fsm:sync_send_event(
Handle1,
{modify_dn, Entry, NewRDN, bool_p(DelOldRDN), optional(NewSup)},
?CALL_TIMEOUT).
%%% --------------------------------------------------------------------
@@ -228,7 +236,7 @@ modify_dn(Handle, Entry, NewRDN, DelOldRDN, NewSup)
bind(Handle, RootDN, Passwd)
when list(RootDN),list(Passwd) ->
Handle1 = get_handle(Handle),
gen_fsm:sync_send_event(Handle1, {bind, RootDN, Passwd}, infinity).
gen_fsm:sync_send_event(Handle1, {bind, RootDN, Passwd}, ?CALL_TIMEOUT).
%%% Sanity checks !
@@ -273,7 +281,7 @@ search(Handle, L) when list(L) ->
call_search(Handle, A) ->
Handle1 = get_handle(Handle),
gen_fsm:sync_send_event(Handle1, {search, A}, infinity).
gen_fsm:sync_send_event(Handle1, {search, A}, ?CALL_TIMEOUT).
parse_search_args(Args) ->
parse_search_args(Args, #eldap_search{scope = wholeSubtree}).
@@ -382,7 +390,7 @@ init({Hosts, Port, Rootdn, Passwd}) ->
passwd = Passwd,
id = 0,
dict = dict:new(),
bind_q = queue:new()}, 0}.
req_q = queue:new()}, 0}.
%%----------------------------------------------------------------------
%% Func: StateName/2
@@ -405,38 +413,20 @@ connecting(timeout, S) ->
%% {stop, Reason, NewStateData} |
%% {stop, Reason, Reply, NewStateData}
%%----------------------------------------------------------------------
connecting(_Event, _From, S) ->
Reply = {error, connecting},
{reply, Reply, connecting, S}.
connecting(Event, From, S) ->
Q = queue:in({Event, From}, S#eldap.req_q),
{next_state, connecting, S#eldap{req_q=Q}}.
wait_bind_response(_Event, _From, S) ->
Reply = {error, wait_bind_response},
{reply, Reply, wait_bind_response, S}.
wait_bind_response(Event, From, S) ->
Q = queue:in({Event, From}, S#eldap.req_q),
{next_state, wait_bind_response, S#eldap{req_q=Q}}.
active_bind(Event, From, S) ->
Q = queue:in({Event, From}, S#eldap.req_q),
{next_state, active_bind, S#eldap{req_q=Q}}.
active(Event, From, S) ->
case catch send_command(Event, From, S) of
{ok, NewS} ->
case Event of
{bind, _, _} ->
{next_state, active_bind, NewS};
_ ->
{next_state, active, NewS}
end;
{error, Reason} ->
{reply, {error, Reason}, active, S};
{'EXIT', Reason} ->
{reply, {error, Reason}, active, S}
end.
active_bind({bind, RootDN, Passwd}, From, #eldap{bind_q=Q} = S) ->
NewQ = queue:in({{bind, RootDN, Passwd}, From}, Q),
{next_state, active_bind, S#eldap{bind_q=NewQ}};
active_bind(Event, From, S) ->
case catch send_command(Event, From, S) of
{ok, NewS} -> {next_state, active_bind, NewS};
{error, Reason} -> {reply, {error, Reason}, active_bind, S};
{'EXIT', Reason} -> {reply, {error, Reason}, active_bind, S}
end.
process_command(S, Event, From).
%%----------------------------------------------------------------------
%% Func: handle_event/3
@@ -446,21 +436,8 @@ active_bind(Event, From, S) ->
%% {stop, Reason, NewStateData}
%%----------------------------------------------------------------------
handle_event(close, _StateName, S) ->
gen_tcp:close(S#eldap.fd),
{stop, closed, S};
handle_event(process_bind_q, active_bind, #eldap{bind_q=Q} = S) ->
case queue:out(Q) of
{{value, {BindEvent, To}}, NewQ} ->
NewStateData = case catch send_command(BindEvent, To, S) of
{ok, NewS} -> NewS;
{error, Reason} -> gen_fsm:reply(To, {error, Reason}), S;
{'EXIT', Reason} -> gen_fsm:reply(To, {error, Reason}), S
end,
{next_state, active_bind, NewStateData#eldap{bind_q=NewQ}};
{empty, Q} ->
{next_state, active, S}
end;
catch gen_tcp:close(S#eldap.fd),
{stop, normal, S};
handle_event(_Event, StateName, S) ->
{next_state, StateName, S}.
@@ -489,59 +466,61 @@ handle_sync_event(_Event, _From, StateName, S) ->
%% Packets arriving in various states
%%
handle_info({tcp, _Socket, Data}, connecting, S) ->
?DEBUG("eldap. tcp packet received when disconnected!~n~p", [Data]),
?DEBUG("tcp packet received when disconnected!~n~p", [Data]),
{next_state, connecting, S};
handle_info({tcp, _Socket, Data}, wait_bind_response, S) ->
cancel_timer(S#eldap.bind_timer),
case catch recvd_wait_bind_response(Data, S) of
bound -> {next_state, active, S};
{fail_bind, _Reason} -> close_and_retry(S),
{next_state, connecting, S#eldap{fd = null}};
{'EXIT', _Reason} -> close_and_retry(S),
{next_state, connecting, S#eldap{fd = null}};
{error, _Reason} -> close_and_retry(S),
{next_state, connecting, S#eldap{fd = null}}
bound ->
dequeue_commands(S);
{fail_bind, _Reason} ->
{next_state, connecting, close_and_retry(S)};
{'EXIT', _Reason} ->
{next_state, connecting, close_and_retry(S)};
{error, _Reason} ->
{next_state, connecting, close_and_retry(S)}
end;
handle_info({tcp, _Socket, Data}, StateName, S)
when StateName==active; StateName==active_bind ->
when StateName == active orelse StateName == active_bind ->
case catch recvd_packet(Data, S) of
{reply, Reply, To, NewS} -> gen_fsm:reply(To, Reply),
{next_state, StateName, NewS};
{ok, NewS} -> {next_state, StateName, NewS};
{'EXIT', _Reason} -> {next_state, StateName, S};
{error, _Reason} -> {next_state, StateName, S}
{response, Response, RequestType} ->
NewS = case Response of
{reply, Reply, To, S1} ->
gen_fsm:reply(To, Reply),
S1;
{ok, S1} ->
S1
end,
if (StateName == active_bind andalso
RequestType == bindRequest) orelse
(StateName == active) ->
dequeue_commands(NewS);
true ->
{next_state, StateName, NewS}
end;
_ ->
{next_state, StateName, S}
end;
handle_info({tcp_closed, _Socket}, Fsm_state, S) ->
?WARNING_MSG("LDAP server closed the connection: ~s:~p~nIn State: ~p",
[S#eldap.host, S#eldap.port ,Fsm_state]),
F = fun(_Id, [{Timer, From, _Name}|_]) ->
gen_fsm:reply(From, {error, tcp_closed}),
cancel_timer(Timer)
end,
dict:map(F, S#eldap.dict),
{ok, NextState, NewS} = connect_bind(S#eldap{fd = null,
dict = dict:new(),
bind_q=queue:new()}),
{next_state, NextState, NewS};
{next_state, connecting, close_and_retry(S)};
handle_info({tcp_error, _Socket, Reason}, Fsm_state, S) ->
?DEBUG("eldap received tcp_error: ~p~nIn State: ~p", [Reason, Fsm_state]),
%% XXX wouldn't it be safer to try reconnect ?
%% if we were waiting a result, we may mait forever
%% cause request is probably lost....
{next_state, Fsm_state, S};
{next_state, connecting, close_and_retry(S)};
%%
%% Timers
%%
handle_info({timeout, Timer, {cmd_timeout, Id}}, active, S) ->
handle_info({timeout, Timer, {cmd_timeout, Id}}, StateName, S) ->
case cmd_timeout(Timer, Id, S) of
{reply, To, Reason, NewS} -> gen_fsm:reply(To, Reason),
{next_state, active, NewS};
{error, _Reason} -> {next_state, active, S}
{next_state, StateName, NewS};
{error, _Reason} -> {next_state, StateName, S}
end;
handle_info({timeout, retry_connect}, connecting, S) ->
@@ -549,8 +528,7 @@ handle_info({timeout, retry_connect}, connecting, S) ->
{next_state, NextState, NewS};
handle_info({timeout, _Timer, bind_timeout}, wait_bind_response, S) ->
close_and_retry(S),
{next_state, connecting, S#eldap{fd = null}};
{next_state, connecting, close_and_retry(S)};
%%
%% Make sure we don't fill the message queue with rubbish
@@ -579,6 +557,34 @@ code_change(_OldVsn, StateName, S, _Extra) ->
%%%----------------------------------------------------------------------
%%% Internal functions
%%%----------------------------------------------------------------------
dequeue_commands(S) ->
case queue:out(S#eldap.req_q) of
{{value, {Event, From}}, Q} ->
case process_command(S#eldap{req_q=Q}, Event, From) of
{_, active, NewS} ->
dequeue_commands(NewS);
Res ->
Res
end;
{empty, _} ->
{next_state, active, S}
end.
process_command(S, Event, From) ->
case send_command(Event, From, S) of
{ok, NewS} ->
case Event of
{bind, _, _} ->
{next_state, active_bind, NewS};
_ ->
{next_state, active, NewS}
end;
{error, _Reason} ->
Q = queue:in_r({Event, From}, S#eldap.req_q),
NewS = close_and_retry(S#eldap{req_q=Q}),
{next_state, connecting, NewS}
end.
send_command(Command, From, S) ->
Id = bump_id(S),
{Name, Request} = gen_req(Command),
@@ -589,7 +595,7 @@ send_command(Command, From, S) ->
case gen_tcp:send(S#eldap.fd, Bytes) of
ok ->
Timer = erlang:start_timer(?CMD_TIMEOUT, self(), {cmd_timeout, Id}),
New_dict = dict:store(Id, [{Timer, From, Name}], S#eldap.dict),
New_dict = dict:store(Id, [{Timer, Command, From, Name}], S#eldap.dict),
{ok, S#eldap{id = Id, dict = New_dict}};
Error ->
Error
@@ -649,6 +655,7 @@ recvd_packet(Pkt, S) ->
Dict = S#eldap.dict,
Id = Msg#'LDAPMessage'.messageID,
{Timer, From, Name, Result_so_far} = get_op_rec(Id, Dict),
Answer =
case {Name, Op} of
{searchRequest, {searchResEntry, R}} when
record(R,'SearchResultEntry') ->
@@ -696,14 +703,14 @@ recvd_packet(Pkt, S) ->
New_dict = dict:erase(Id, Dict),
cancel_timer(Timer),
Reply = check_bind_reply(Result, From),
gen_fsm:send_all_state_event(self(), process_bind_q),
{reply, Reply, From, S#eldap{dict = New_dict}};
{OtherName, OtherResult} ->
New_dict = dict:erase(Id, Dict),
cancel_timer(Timer),
{reply, {error, {invalid_result, OtherName, OtherResult}},
From, S#eldap{dict = New_dict}}
end;
end,
{response, Answer, Name};
Error -> Error
end.
@@ -723,7 +730,7 @@ check_bind_reply(Other, _From) ->
get_op_rec(Id, Dict) ->
case dict:find(Id, Dict) of
{ok, [{Timer, From, Name}|Res]} ->
{ok, [{Timer, _Command, From, Name}|Res]} ->
{Timer, From, Name, Res};
error ->
throw({error, unkown_id})
@@ -784,13 +791,16 @@ check_tag(Data) ->
end.
close_and_retry(S) ->
gen_tcp:close(S#eldap.fd),
retry_connect().
retry_connect() ->
erlang:send_after(?RETRY_TIMEOUT, self(),
{timeout, retry_connect}).
catch gen_tcp:close(S#eldap.fd),
Queue = dict:fold(
fun(_Id, [{Timer, Command, From, _Name}|_], Q) ->
cancel_timer(Timer),
queue:in_r({Command, From}, Q);
(_, _, Q) ->
Q
end, S#eldap.req_q, S#eldap.dict),
erlang:send_after(?RETRY_TIMEOUT, self(), {timeout, retry_connect}),
S#eldap{fd=null, req_q=Queue, dict=dict:new()}.
%%-----------------------------------------------------------------------
%% Sort out timed out commands
@@ -798,7 +808,7 @@ retry_connect() ->
cmd_timeout(Timer, Id, S) ->
Dict = S#eldap.dict,
case dict:find(Id, Dict) of
{ok, [{Timer, From, Name}|Res]} ->
{ok, [{Timer, _Command, From, Name}|Res]} ->
case Name of
searchRequest ->
{Res1, Ref1} = polish(Res),
@@ -841,7 +851,8 @@ polish([], Res, Ref) ->
%%-----------------------------------------------------------------------
connect_bind(S) ->
Host = next_host(S#eldap.host, S#eldap.hosts),
TcpOpts = [{packet, asn1}, {active, true}, {keepalive, true}, binary],
TcpOpts = [{packet, asn1}, {active, true}, {keepalive, true},
{send_timeout, ?SEND_TIMEOUT}, binary],
?INFO_MSG("LDAP connection on ~s:~p", [Host, S#eldap.port]),
case gen_tcp:connect(Host, S#eldap.port, TcpOpts) of
{ok, Socket} ->
@@ -853,15 +864,16 @@ connect_bind(S) ->
host = Host,
bind_timer = Timer}};
{error, Reason} ->
?ERROR_MSG("LDAP bind failed on ~s:~p~nReason: ~p", [Host, S#eldap.port, Reason]),
gen_tcp:close(Socket),
retry_connect(),
{ok, connecting, S#eldap{host = Host}}
?ERROR_MSG("LDAP bind failed on ~s:~p~nReason: ~p",
[Host, S#eldap.port, Reason]),
NewS = close_and_retry(S),
{ok, connecting, NewS#eldap{host = Host}}
end;
{error, Reason} ->
?ERROR_MSG("LDAP connection failed on ~s:~p~nReason: ~p", [Host, S#eldap.port, Reason]),
retry_connect(),
{ok, connecting, S#eldap{host = Host}}
?ERROR_MSG("LDAP connection failed on ~s:~p~nReason: ~p",
[Host, S#eldap.port, Reason]),
NewS = close_and_retry(S),
{ok, connecting, NewS#eldap{host = Host}}
end.
bind_request(Socket, S) ->
+2
View File
@@ -14,6 +14,8 @@
* Workaround for EI encode_string bug
*/
int x_fix_buff(ei_x_buff* x, int szneeded);
#define put8(s,n) do { \
(s)[0] = (char)((n) & 0xff); \
(s) += 1; \
+18 -20
View File
@@ -35,7 +35,7 @@
note_caps/3,
clear_caps/1,
get_features/2,
get_user_resource/2,
get_user_resources/2,
handle_disco_response/3]).
%% gen_mod callbacks
@@ -61,7 +61,7 @@
-record(caps, {node, version, exts}).
-record(caps_features, {node_pair, features}).
-record(user_caps, {jid, caps}).
-record(user_caps_default, {uid, resource}).
-record(user_caps_resources, {uid, resource}).
-record(state, {host,
disco_requests = ?DICT:new(),
feature_queries = []}).
@@ -109,21 +109,17 @@ clear_caps(JID) ->
BJID = list_to_binary(jlib:jid_to_string(JID)),
BUID = list_to_binary(jlib:jid_to_string({U, S, []})),
catch mnesia:dirty_delete({user_caps, BJID}),
case catch mnesia:dirty_read({user_caps_default, BUID}) of
[#user_caps_default{resource=R}] ->
catch mnesia:dirty_delete({user_caps_default, BUID});
_ ->
ok
end.
catch mnesia:dirty_delete_object(#user_caps_resources{uid = BUID, resource = list_to_binary(R)}),
ok.
%% give default user resource
get_user_resource(LUser, LServer) ->
get_user_resources(LUser, LServer) ->
BUID = list_to_binary(jlib:jid_to_string({LUser, LServer, []})),
case catch mnesia:dirty_read({user_caps_default, BUID}) of
[#user_caps_default{resource=R}] ->
R;
_ ->
[]
case catch mnesia:dirty_read({user_caps_resources, BUID}) of
{'EXIT', _} ->
[];
Resources ->
lists:map(fun(#user_caps_resources{resource=R}) -> binary_to_list(R) end, Resources)
end.
%% note_caps should be called to make the module request disco
@@ -180,9 +176,11 @@ init([Host, _Opts]) ->
mnesia:create_table(user_caps,
[{disc_copies, [node()]},
{attributes, record_info(fields, user_caps)}]),
mnesia:create_table(user_caps_default,
mnesia:create_table(user_caps_resources,
[{disc_copies, [node()]},
{attributes, record_info(fields, user_caps_default)}]),
{type, bag},
{attributes, record_info(fields, user_caps_resources)}]),
mnesia:delete_table(user_caps_default),
{ok, #state{host = Host}}.
maybe_get_features(#caps{node = Node, version = Version, exts = Exts}) ->
@@ -239,11 +237,11 @@ handle_cast({note_caps, From,
mnesia:dirty_write(#user_caps{jid = BJID, caps = Caps}),
case ejabberd_sm:get_user_resources(U, S) of
[] ->
ok;
_ ->
% only store default resource of external contacts
% only store resources of caps aware external contacts
BUID = list_to_binary(jlib:jid_to_string(jlib:jid_remove_resource(From))),
mnesia:dirty_write(#user_caps_default{uid = BUID, resource = R})
mnesia:dirty_write(#user_caps_resources{uid = BUID, resource = list_to_binary(R)});
_ ->
ok
end,
SubNodes = [Version | Exts],
%% Now, find which of these are not already in the database.
+2 -1
View File
@@ -701,7 +701,8 @@ htmlize2(S1, NoFollow) ->
S2 = element(2, regexp:gsub(S1, "\\&", "\\&amp;")),
S3 = element(2, regexp:gsub(S2, "<", "\\&lt;")),
S4 = element(2, regexp:gsub(S3, ">", "\\&gt;")),
S5 = element(2, regexp:gsub(S4, "[-+.a-zA-Z0-9]+://[^] )\'\"}]+", link_regexp(NoFollow))),
S5 = element(2, regexp:gsub(S4, "(http|https|ftp|mailto|xmpp)://[^] )\'\"}]+",
link_regexp(NoFollow))),
%% Remove 'right-to-left override' unicode character 0x202e
element(2, regexp:gsub(S5, [226,128,174], "[RLO]")).
+3 -2
View File
@@ -1461,7 +1461,7 @@ add_new_user(From, Nick, {xmlelement, _, Attrs, Els} = Packet, StateData) ->
From, Err),
StateData;
{_, _, _, Role} ->
case check_password(Affiliation, Els, StateData) of
case check_password(ServiceAffiliation, Els, StateData) of
true ->
NewState =
add_user_presence(
@@ -1518,8 +1518,9 @@ add_new_user(From, Nick, {xmlelement, _, Attrs, Els} = Packet, StateData) ->
end.
check_password(owner, _Els, _StateData) ->
%% Don't check pass if user is owner in MUC service (access_admin option)
true;
check_password(_Affiliation, Els, StateData) ->
check_password(_ServiceAffiliation, Els, StateData) ->
case (StateData#state.config)#config.password_protected of
false ->
true;
+2 -1
View File
@@ -414,7 +414,8 @@ parse_items(Els) ->
parse_items(Els, []).
parse_items([], Res) ->
lists:reverse(Res);
%% Sort the items by their 'order' attribute
lists:keysort(#listitem.order, Res);
parse_items([{xmlelement, "item", Attrs, SubEls} | Els], Res) ->
Type = xml:get_attr("type", Attrs),
Value = xml:get_attr("value", Attrs),
+2 -1
View File
@@ -414,7 +414,8 @@ parse_items(Els) ->
parse_items(Els, []).
parse_items([], Res) ->
lists:reverse(Res);
%% Sort the items by their 'order' attribute
lists:keysort(#listitem.order, Res);
parse_items([{xmlelement, "item", Attrs, SubEls} | Els], Res) ->
Type = xml:get_attr("type", Attrs),
Value = xml:get_attr("value", Attrs),
+7 -11
View File
@@ -197,9 +197,9 @@ parse_options(ServerHost, Opts) ->
ACL = gen_mod:get_opt(access, Opts, all),
Name = gen_mod:get_opt(name, Opts, "SOCKS5 Bytestreams"),
IP = case gen_mod:get_opt(ip, Opts, none) of
none -> get_proxy_or_domainip(ServerHost, MyHost);
Addr -> Addr
end,
none -> get_my_ip();
Addr -> Addr
end,
StrIP = inet_parse:ntoa(IP),
StreamAddr = [{"jid", MyHost}, {"host", StrIP}, {"port", integer_to_list(Port)}],
{IP, #state{myhost = MyHost,
@@ -209,13 +209,9 @@ parse_options(ServerHost, Opts) ->
stream_addr = StreamAddr,
acl = ACL}}.
%% Return the IP of the proxy host, or if not found, the ip of the xmpp domain
get_proxy_or_domainip(ServerHost, MyHost) ->
case inet:getaddr(MyHost, inet) of
get_my_ip() ->
{ok, MyHostName} = inet:gethostname(),
case inet:getaddr(MyHostName, inet) of
{ok, Addr} -> Addr;
{error, _} ->
case inet:getaddr(ServerHost, inet) of
{ok, Addr} -> Addr;
{error, _} -> {127,0,0,1}
end
{error, _} -> {127,0,0,1}
end.
+105 -86
View File
@@ -41,7 +41,7 @@
-module(mod_pubsub).
-author('christophe.romain@process-one.net').
-version('1.12-01').
-version('1.12-02').
-behaviour(gen_server).
-behaviour(gen_mod).
@@ -56,6 +56,7 @@
%% exports for hooks
-export([presence_probe/3,
out_subscription/4,
remove_user/2,
disco_local_identity/5,
disco_local_features/5,
@@ -163,6 +164,7 @@ init([ServerHost, Opts]) ->
ejabberd_hooks:add(disco_sm_features, ServerHost, ?MODULE, disco_sm_features, 75),
ejabberd_hooks:add(disco_sm_items, ServerHost, ?MODULE, disco_sm_items, 75),
ejabberd_hooks:add(presence_probe_hook, ServerHost, ?MODULE, presence_probe, 50),
ejabberd_hooks:add(roster_out_subscription, ServerHost, ?MODULE, out_subscription, 50),
ejabberd_hooks:add(remove_user, ServerHost, ?MODULE, remove_user, 50),
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
lists:foreach(
@@ -235,6 +237,8 @@ init_nodes(Host, ServerHost, ServedHosts) ->
ok.
update_database(Host) ->
mnesia:del_table_index(pubsub_node, type),
mnesia:del_table_index(pubsub_node, parentid),
case catch mnesia:table_info(pubsub_node, attributes) of
[host_node, host_parent, info] ->
?INFO_MSG("upgrade pubsub tables",[]),
@@ -409,10 +413,28 @@ disco_sm_items(Acc, _From, To, Node, _Lang) ->
%% presence hooks handling functions
%%
presence_probe(#jid{lserver = Host} = JID, JID, Pid) ->
presence_probe(#jid{luser = User, lserver = Server, lresource = Resource} = JID, JID, _Pid) ->
Proc = gen_mod:get_module_proc(Server, ?PROCNAME),
gen_server:cast(Proc, {presence, JID}),
gen_server:cast(Proc, {presence, User, Server, [Resource], JID});
presence_probe(#jid{luser = User, lserver = Server, lresource = Resource}, #jid{lserver = Host} = JID, _Pid) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
gen_server:cast(Proc, {presence, JID, Pid});
presence_probe(_, _, _) ->
gen_server:cast(Proc, {presence, User, Server, [Resource], JID}).
%% -------
%% subscription hooks handling functions
%%
out_subscription(User, Server, JID, subscribed) ->
Owner = jlib:make_jid(User, Server, ""),
{PUser, PServer, PResource} = jlib:jid_tolower(JID),
PResources = case PResource of
[] -> user_resources(PUser, PServer);
_ -> [PResource]
end,
Proc = gen_mod:get_module_proc(Server, ?PROCNAME),
gen_server:cast(Proc, {presence, PUser, PServer, PResources, Owner});
out_subscription(_, _, _, _) ->
ok.
%% -------
@@ -452,11 +474,9 @@ handle_call(stop, _From, State) ->
%% Description: Handling cast messages
%%--------------------------------------------------------------------
%% @private
handle_cast({presence, JID, Pid}, State) ->
handle_cast({presence, JID}, State) ->
%% A new resource is available. send last published items
LJID = jlib:jid_tolower(JID),
Host = State#state.host,
ServerHost = State#state.server_host,
%% for each node From is subscribed to
%% and if the node is so configured, send the last published item to From
lists:foreach(fun(Type) ->
@@ -478,42 +498,43 @@ handle_cast({presence, JID, Pid}, State) ->
ok
end, Subscriptions)
end, State#state.plugins),
%% and send to From last PEP events published by its contacts
case catch ejabberd_c2s:get_subscribed(Pid) of
Contacts when is_list(Contacts) ->
lists:foreach(
fun({User, Server, _}) ->
Owner = {User, Server, ""},
lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, options = Options}) ->
case get_option(Options, send_last_published_item) of
on_sub_and_presence ->
case is_caps_notify(ServerHost, Node, LJID) of
true ->
Subscribed = case get_option(Options, access_model) of
open -> true;
presence -> true;
whitelist -> false; % subscribers are added manually
authorize -> false; % likewise
roster ->
Grps = get_option(Options, roster_groups_allowed, []),
element(2, get_roster_info(User, Server, LJID, Grps))
end,
if Subscribed ->
send_last_item(Owner, Node, LJID);
true ->
ok
end;
false ->
ok
end;
_ ->
{noreply, State};
handle_cast({presence, User, Server, Resources, JID}, State) ->
%% A new resource is available. send last published PEP items
Owner = jlib:jid_remove_resource(jlib:jid_tolower(JID)),
Host = State#state.host,
ServerHost = State#state.server_host,
lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, options = Options}) ->
case get_option(Options, send_last_published_item) of
on_sub_and_presence ->
lists:foreach(fun(Resource) ->
LJID = {User, Server, Resource},
case is_caps_notify(ServerHost, Node, LJID) of
true ->
Subscribed = case get_option(Options, access_model) of
open -> true;
presence -> true;
whitelist -> false; % subscribers are added manually
authorize -> false; % likewise
roster ->
Grps = get_option(Options, roster_groups_allowed, []),
{OU, OS, _} = Owner,
element(2, get_roster_info(OU, OS, LJID, Grps))
end,
if Subscribed ->
send_last_item(Owner, Node, LJID);
true ->
ok
end
end, tree_action(Host, get_nodes, [Owner]))
end, Contacts);
_ ->
ok
end,
end;
false ->
ok
end
end, Resources);
_ ->
ok
end
end, tree_action(Host, get_nodes, [Owner])),
{noreply, State};
handle_cast({remove_user, LUser, LServer}, State) ->
@@ -580,6 +601,7 @@ terminate(_Reason, #state{host = Host,
ejabberd_hooks:delete(disco_sm_features, ServerHost, ?MODULE, disco_sm_features, 75),
ejabberd_hooks:delete(disco_sm_items, ServerHost, ?MODULE, disco_sm_items, 75),
ejabberd_hooks:delete(presence_probe_hook, ServerHost, ?MODULE, presence_probe, 50),
ejabberd_hooks:delete(roster_out_subscription, ServerHost, ?MODULE, out_subscription, 50),
ejabberd_hooks:delete(remove_user, ServerHost, ?MODULE, remove_user, 50),
lists:foreach(fun({NS,Mod}) ->
gen_iq_handler:remove_iq_handler(Mod, ServerHost, NS)
@@ -869,30 +891,25 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, _Lang, Access, Plugins) ->
end,
case {IQType, Name} of
{set, "create"} ->
case Configuration of
[{xmlelement, "configure", _, Config}] ->
%% Get the type of the node
Type = case xml:get_attr_s("type", Attrs) of
[] -> hd(Plugins);
T -> T
end,
%% we use Plugins list matching because we do not want to allocate
%% atoms for non existing type, this prevent atom allocation overflow
case lists:member(Type, Plugins) of
false ->
{error, extended_error(
?ERR_FEATURE_NOT_IMPLEMENTED,
unsupported, "create-nodes")};
true ->
create_node(Host, ServerHost, Node, From,
Type, Access, Config)
end;
_ ->
%% this breaks backward compatibility!
%% can not create node without <configure/>
%% but this is the new spec anyway
?INFO_MSG("Node ~p ; invalid configuration: ~p", [Node, Configuration]),
{error, ?ERR_BAD_REQUEST}
Config = case Configuration of
[{xmlelement, "configure", _, C}] -> C;
_ -> []
end,
%% Get the type of the node
Type = case xml:get_attr_s("type", Attrs) of
[] -> hd(Plugins);
T -> T
end,
%% we use Plugins list matching because we do not want to allocate
%% atoms for non existing type, this prevent atom allocation overflow
case lists:member(Type, Plugins) of
false ->
{error, extended_error(
?ERR_FEATURE_NOT_IMPLEMENTED,
unsupported, "create-nodes")};
true ->
create_node(Host, ServerHost, Node, From,
Type, Access, Config)
end;
{set, "publish"} ->
case xml:remove_cdata(Els) of
@@ -1961,7 +1978,7 @@ get_subscriptions(Host, Node, JID) ->
if
not RetrieveFeature ->
%% Service does not support manage subscriptions
{error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "manage-affiliations")};
{error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "manage-subscriptions")};
Affiliation /= {result, owner} ->
%% Entity is not an owner
{error, ?ERR_FORBIDDEN};
@@ -2299,7 +2316,10 @@ broadcast_stanza(Host, NodeOpts, States, Stanza) ->
%% broadcast Stanza to all contacts of the user that are advertising
%% interest in this kind of Node.
broadcast_by_caps({LUser, LServer, LResource}, Node, _Type, Stanza) ->
SenderResource = user_resource(LUser, LServer, LResource),
SenderResource = case LResource of
[] -> hd(user_resources(LUser, LServer));
_ -> LResource
end,
case ejabberd_sm:get_session_pid(LUser, LServer, SenderResource) of
C2SPid when is_pid(C2SPid) ->
%% set the from address on the notification to the bare JID of the account owner
@@ -2309,14 +2329,17 @@ broadcast_by_caps({LUser, LServer, LResource}, Node, _Type, Stanza) ->
%%ReplyTo = jlib:make_jid(LUser, LServer, SenderResource), % This has to be used
case catch ejabberd_c2s:get_subscribed(C2SPid) of
Contacts when is_list(Contacts) ->
lists:foreach(fun({U, S, R}) ->
LJID = {U, S, user_resource(U, S, R)},
case is_caps_notify(LServer, Node, LJID) of
true ->
ejabberd_router ! {route, Sender, jlib:make_jid(LJID), Stanza};
false ->
ok
end
lists:foreach(fun({U, S, _}) ->
JIDs = lists:foldl(fun(R, Acc) ->
LJID = {U, S, R},
case is_caps_notify(LServer, Node, LJID) of
true -> [LJID | Acc];
false -> Acc
end
end, [], user_resources(U, S)),
lists:foreach(fun(JID) ->
ejabberd_router ! {route, Sender, jlib:make_jid(JID), Stanza}
end, JIDs)
end, Contacts);
_ ->
ok
@@ -2331,15 +2354,11 @@ broadcast_by_caps(_, _, _, _) ->
%% If we don't know the resource, just pick first if any
%% If no resource available, check if caps anyway (remote online)
user_resource(LUser, LServer, []) ->
case ejabberd_sm:get_user_resources(LUser, LServer) of
[R|_] ->
R;
[] ->
mod_caps:get_user_resource(LUser, LServer)
end;
user_resource(_, _, LResource) ->
LResource.
user_resources(User, Server) ->
case ejabberd_sm:get_user_resources(User, Server) of
[] -> mod_caps:get_user_resources(User, Server);
Rs -> Rs
end.
is_caps_notify(Host, Node, LJID) ->
case mod_caps:get_caps(LJID) of
@@ -2698,7 +2717,7 @@ tree_call({_User, Server, _Resource}, Function, Args) ->
tree_call(Host, Function, Args) ->
Module = case ets:lookup(gen_mod:get_module_proc(Host, pubsub_state), nodetree) of
[{nodetree, N}] -> N;
_ -> list_to_atom(?TREE_PREFIX ++ ?STDNODE)
_ -> list_to_atom(?TREE_PREFIX ++ ?STDTREE)
end,
catch apply(Module, Function, Args).
tree_action(Host, Function, Args) ->
+48 -29
View File
@@ -253,34 +253,7 @@ process_item_set(From, To, {xmlelement, _Name, Attrs, Els}) ->
push_item(User, LServer, To, Item),
case Item#roster.subscription of
remove ->
IsTo = case OldItem#roster.subscription of
both -> true;
to -> true;
_ -> false
end,
IsFrom = case OldItem#roster.subscription of
both -> true;
from -> true;
_ -> false
end,
if IsTo ->
ejabberd_router:route(
jlib:jid_remove_resource(From),
jlib:make_jid(OldItem#roster.jid),
{xmlelement, "presence",
[{"type", "unsubscribe"}],
[]});
true -> ok
end,
if IsFrom ->
ejabberd_router:route(
jlib:jid_remove_resource(From),
jlib:make_jid(OldItem#roster.jid),
{xmlelement, "presence",
[{"type", "unsubscribed"}],
[]});
true -> ok
end,
send_unsubscribing_presence(From, OldItem),
ok;
_ ->
ok
@@ -371,7 +344,7 @@ push_item(User, Server, Resource, _From, Item) ->
push_item(User, Server, Resource, From, Item) ->
ResIQ = #iq{type = set, xmlns = ?NS_ROSTER,
id = "push",
id = "push" ++ randoms:get_string(),
sub_el = [{xmlelement, "query",
[{"xmlns", ?NS_ROSTER}],
[item_to_xml(Item)]}]},
@@ -607,6 +580,7 @@ remove_user(User, Server) ->
LUser = jlib:nodeprep(User),
LServer = jlib:nameprep(Server),
US = {LUser, LServer},
send_unsubscription_to_rosteritems(LUser, LServer),
F = fun() ->
lists:foreach(fun(R) ->
mnesia:delete_object(R)
@@ -615,6 +589,51 @@ remove_user(User, Server) ->
end,
mnesia:transaction(F).
%% For each contact with Subscription:
%% Both or From, send a "unsubscribed" presence stanza;
%% Both or To, send a "unsubscribe" presence stanza.
send_unsubscription_to_rosteritems(LUser, LServer) ->
RosterItems = get_user_roster([], {LUser, LServer}),
From = jlib:make_jid({LUser, LServer, ""}),
lists:foreach(fun(RosterItem) ->
send_unsubscribing_presence(From, RosterItem)
end,
RosterItems).
%% @spec (From::jid(), Item::roster()) -> ok
send_unsubscribing_presence(From, Item) ->
IsTo = case Item#roster.subscription of
both -> true;
to -> true;
_ -> false
end,
IsFrom = case Item#roster.subscription of
both -> true;
from -> true;
_ -> false
end,
if IsTo ->
send_presence_type(
jlib:jid_remove_resource(From),
jlib:make_jid(Item#roster.jid), "unsubscribe");
true -> ok
end,
if IsFrom ->
send_presence_type(
jlib:jid_remove_resource(From),
jlib:make_jid(Item#roster.jid), "unsubscribed");
true -> ok
end,
ok.
send_presence_type(From, To, Type) ->
ejabberd_router:route(
From, To,
{xmlelement, "presence",
[{"type", Type}],
[]}).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
set_items(User, Server, SubEl) ->
+48 -29
View File
@@ -295,34 +295,7 @@ process_item_set(From, To, {xmlelement, _Name, Attrs, Els}) ->
push_item(User, LServer, To, Item),
case Item#roster.subscription of
remove ->
IsTo = case OldItem#roster.subscription of
both -> true;
to -> true;
_ -> false
end,
IsFrom = case OldItem#roster.subscription of
both -> true;
from -> true;
_ -> false
end,
if IsTo ->
ejabberd_router:route(
jlib:jid_remove_resource(From),
jlib:make_jid(OldItem#roster.jid),
{xmlelement, "presence",
[{"type", "unsubscribe"}],
[]});
true -> ok
end,
if IsFrom ->
ejabberd_router:route(
jlib:jid_remove_resource(From),
jlib:make_jid(OldItem#roster.jid),
{xmlelement, "presence",
[{"type", "unsubscribed"}],
[]});
true -> ok
end,
send_unsubscribing_presence(From, OldItem),
ok;
_ ->
ok
@@ -407,7 +380,7 @@ push_item(User, Server, Resource, _From, Item) ->
push_item(User, Resource, From, Item) ->
ResIQ = #iq{type = set, xmlns = ?NS_ROSTER,
id = "push",
id = "push" ++ randoms:get_string(),
sub_el = [{xmlelement, "query",
[{"xmlns", ?NS_ROSTER}],
[item_to_xml(Item)]}]},
@@ -669,9 +642,55 @@ remove_user(User, Server) ->
LUser = jlib:nodeprep(User),
LServer = jlib:nameprep(Server),
Username = ejabberd_odbc:escape(LUser),
send_unsubscription_to_rosteritems(LUser, LServer),
odbc_queries:del_user_roster_t(LServer, Username),
ok.
%% For each contact with Subscription:
%% Both or From, send a "unsubscribed" presence stanza;
%% Both or To, send a "unsubscribe" presence stanza.
send_unsubscription_to_rosteritems(LUser, LServer) ->
RosterItems = get_user_roster([], {LUser, LServer}),
From = jlib:make_jid({LUser, LServer, ""}),
lists:foreach(fun(RosterItem) ->
send_unsubscribing_presence(From, RosterItem)
end,
RosterItems).
%% @spec (From::jid(), Item::roster()) -> ok
send_unsubscribing_presence(From, Item) ->
IsTo = case Item#roster.subscription of
both -> true;
to -> true;
_ -> false
end,
IsFrom = case Item#roster.subscription of
both -> true;
from -> true;
_ -> false
end,
if IsTo ->
send_presence_type(
jlib:jid_remove_resource(From),
jlib:make_jid(Item#roster.jid), "unsubscribe");
true -> ok
end,
if IsFrom ->
send_presence_type(
jlib:jid_remove_resource(From),
jlib:make_jid(Item#roster.jid), "unsubscribed");
true -> ok
end,
ok.
send_presence_type(From, To, Type) ->
ejabberd_router:route(
From, To,
{xmlelement, "presence",
[{"type", Type}],
[]}).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
set_items(User, Server, SubEl) ->
+40 -7
View File
@@ -187,7 +187,24 @@ process_item(RosterItem, Host) ->
%% Check if the list of groups of the new roster item
%% include at least a new one
case lists:subtract(RosterItem#roster.groups, CommonGroups) of
%% If it doesn't, then remove this user from any
%% existing roster groups.
[] ->
%% Remove pending subscription by setting it
%% unsubscribed.
Mod = get_roster_mod(ServerFrom),
%% Remove pending out subscription
Mod:out_subscription(UserTo, ServerTo,
jlib:make_jid(UserFrom, ServerFrom, ""),
unsubscribe),
%% Remove pending in subscription
Mod:in_subscription(aaaa, UserFrom, ServerFrom,
jlib:make_jid(UserTo, ServerTo, ""),
unsubscribe, ""),
%% But we're still subscribed, so respond as such.
RosterItem#roster{subscription = both, ask = none};
%% If so, it means the user wants to add that contact
%% to his personal roster
@@ -212,11 +229,7 @@ build_roster_record(User1, Server1, User2, Server2, Name2, Groups) ->
set_new_rosteritems(UserFrom, ServerFrom,
UserTo, ServerTo, ResourceTo, NameTo, GroupsFrom) ->
Mod = case lists:member(mod_roster_odbc,
gen_mod:loaded_modules(ServerFrom)) of
true -> mod_roster_odbc;
false -> mod_roster
end,
Mod = get_roster_mod(ServerFrom),
RIFrom = build_roster_record(UserFrom, ServerFrom,
UserTo, ServerTo, NameTo, GroupsFrom),
@@ -248,7 +261,7 @@ set_new_rosteritems(UserFrom, ServerFrom,
set_item(User, Server, Resource, Item) ->
ResIQ = #iq{type = set, xmlns = ?NS_ROSTER,
id = "push",
id = "push" ++ randoms:get_string(),
sub_el = [{xmlelement, "query",
[{"xmlns", ?NS_ROSTER}],
[mod_roster:item_to_xml(Item)]}]},
@@ -302,6 +315,18 @@ get_jid_info({Subscription, Groups}, User, Server, JID) ->
in_subscription(Acc, User, Server, JID, Type, _Reason) ->
process_subscription(in, User, Server, JID, Type, Acc).
out_subscription(UserFrom, ServerFrom, JIDTo, unsubscribed) ->
Mod = get_roster_mod(ServerFrom),
%% Remove pending out subscription
#jid{luser = UserTo, lserver = ServerTo} = JIDTo,
JIDFrom = jlib:make_jid(UserFrom, UserTo, ""),
Mod:out_subscription(UserTo, ServerTo, JIDFrom, unsubscribe),
%% Remove pending in subscription
Mod:in_subscription(aaaa, UserFrom, ServerFrom, JIDTo, unsubscribe, ""),
process_subscription(out, UserFrom, ServerFrom, JIDTo, unsubscribed, false);
out_subscription(User, Server, JID, Type) ->
process_subscription(out, User, Server, JID, Type, false).
@@ -617,7 +642,7 @@ push_item(User, Server, From, Item) ->
Item#roster.subscription}]}),
Stanza = jlib:iq_to_xml(
#iq{type = set, xmlns = ?NS_ROSTER,
id = "push",
id = "push" ++ randoms:get_string(),
sub_el = [{xmlelement, "query",
[{"xmlns", ?NS_ROSTER}],
[item_to_xml(Item)]}]}),
@@ -910,6 +935,14 @@ shared_roster_group_parse_query(Host, Group, Query) ->
nothing
end.
%% Get the roster module for Server.
get_roster_mod(Server) ->
case lists:member(mod_roster_odbc,
gen_mod:loaded_modules(Server)) of
true -> mod_roster_odbc;
false -> mod_roster
end.
get_opt(Opts, Opt, Default) ->
case lists:keysearch(Opt, 1, Opts) of
{value, {_, Val}} ->
+1 -1
View File
@@ -148,7 +148,7 @@ CREATE TABLE private_storage (
CREATE INDEX i_private_storage_username USING BTREE ON private_storage(username);
CREATE UNIQUE INDEX i_private_storage_username_namespace USING BTREE ON private_storage(username(75), namespace(75));
--- To update from 1.x:
-- To update from 1.x:
-- ALTER TABLE rosterusers ADD COLUMN askmessage text AFTER ask;
-- UPDATE rosterusers SET askmessage = '';
-- ALTER TABLE rosterusers ALTER COLUMN askmessage SET NOT NULL;
+2 -2
View File
@@ -146,14 +146,14 @@ CREATE INDEX i_private_storage_username ON private_storage USING btree (username
CREATE UNIQUE INDEX i_private_storage_username_namespace ON private_storage USING btree (username, namespace);
--- To update from 0.9.8:
-- To update from 0.9.8:
-- CREATE SEQUENCE spool_seq_seq;
-- ALTER TABLE spool ADD COLUMN seq integer;
-- ALTER TABLE spool ALTER COLUMN seq SET DEFAULT nextval('spool_seq_seq');
-- UPDATE spool SET seq = DEFAULT;
-- ALTER TABLE spool ALTER COLUMN seq SET NOT NULL;
--- To update from 1.x:
-- To update from 1.x:
-- ALTER TABLE rosterusers ADD COLUMN askmessage text;
-- UPDATE rosterusers SET askmessage = '';
-- ALTER TABLE rosterusers ALTER COLUMN askmessage SET NOT NULL;
+6 -1
View File
@@ -40,6 +40,10 @@ typedef struct {
typedef unsigned __int32 uint32_t;
#endif
#ifndef SSL_OP_NO_TICKET
#define SSL_OP_NO_TICKET 0
#endif
/*
* str_hash is based on the public domain code from
* http://www.burtleburtle.net/bob/hash/doobs.html
@@ -340,6 +344,7 @@ static int tls_drv_control(ErlDrvData handle,
res = SSL_CTX_check_private_key(ctx);
die_unless(res > 0, "SSL_CTX_check_private_key failed");
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
SSL_CTX_set_default_verify_paths(ctx);
if (command == SET_CERTIFICATE_FILE_ACCEPT)
@@ -367,7 +372,7 @@ static int tls_drv_control(ErlDrvData handle,
if (command == SET_CERTIFICATE_FILE_ACCEPT)
SSL_set_accept_state(d->ssl);
else {
SSL_set_options(d->ssl, SSL_OP_NO_SSLv2);
SSL_set_options(d->ssl, SSL_OP_NO_SSLv2|SSL_OP_NO_TICKET);
SSL_set_connect_state(d->ssl);
}
break;
+7 -7
View File
@@ -328,6 +328,13 @@ process_request(#state{request_method = 'POST',
socket = Socket,
request_handlers = RequestHandlers} = State)
when is_integer(Len) ->
{ok, IP} =
case SockMod of
gen_tcp ->
inet:peername(Socket);
_ ->
SockMod:peername(Socket)
end,
case SockMod of
gen_tcp ->
inet:setopts(Socket, [{packet, 0}]);
@@ -347,13 +354,6 @@ process_request(#state{request_method = 'POST',
LQ ->
LQ
end,
{ok, IP} =
case SockMod of
gen_tcp ->
inet:peername(Socket);
_ ->
SockMod:peername(Socket)
end,
Request = #request{method = 'POST',
path = LPath,
q = LQuery,
+122
View File
@@ -0,0 +1,122 @@
%%%----------------------------------------------------------------------
%%% File : win32_dns.erl
%%% Author : Geoff Cant
%%% Purpose : Get name servers in a Windows machine
%%% Created : 5 Mar 2009 by Geoff Cant
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
%%% 02111-1307 USA
%%%
%%%----------------------------------------------------------------------
-module(win32_dns).
-export([get_nameservers/0]).
-define(IF_KEY, "\\hklm\\system\\CurrentControlSet\\Services\\TcpIp\\Parameters\\Interfaces").
-define(TOP_KEY, "\\hklm\\system\\CurrentControlSet\\Services\\TcpIp\\Parameters").
get_nameservers() ->
{_, Config} = pick_config(),
IPTs = get_value(["NameServer"], Config),
lists:filter(fun(IPTuple) -> is_good_ns(IPTuple) end, IPTs).
is_good_ns(Addr) ->
element(1,
inet_res:nnslookup("a.root-servers.net", in, any, [{Addr,53}],
timer:seconds(5)
)
) =:= ok.
reg() ->
{ok, R} = win32reg:open([read]),
R.
interfaces(R) ->
ok = win32reg:change_key(R, ?IF_KEY),
{ok, I} = win32reg:sub_keys(R),
I.
config_keys(R, Key) ->
ok = win32reg:change_key(R, Key),
[ {K,
case win32reg:value(R, K) of
{ok, V} -> translate(K, V);
_ -> undefined
end
} || K <- ["Domain", "DhcpDomain",
"NameServer", "DhcpNameServer", "SearchList"]].
translate(NS, V) when NS =:= "NameServer"; NS =:= "DhcpNameServer" ->
IPsStrings = [string:tokens(IP, ".") || IP <- string:tokens(V, ",")],
[ list_to_tuple([list_to_integer(String) || String <- IpStrings])
|| IpStrings <- IPsStrings];
translate(_, V) -> V.
interface_configs(R) ->
[{If, config_keys(R, ?IF_KEY ++ "\\" ++ If)}
|| If <- interfaces(R)].
sort_configs(Configs) ->
lists:sort(fun ({_, A}, {_, B}) ->
ANS = proplists:get_value("NameServer", A),
BNS = proplists:get_value("NameServer", B),
if ANS =/= undefined, BNS =:= undefined -> false;
true -> count_undef(A) < count_undef(B)
end
end,
Configs).
count_undef(L) when is_list(L) ->
lists:foldl(fun ({_K, undefined}, Acc) -> Acc +1;
({_K, []}, Acc) -> Acc +1;
(_, Acc) -> Acc
end, 0, L).
all_configs() ->
R = reg(),
TopConfig = config_keys(R, ?TOP_KEY),
Configs = [{top, TopConfig}
| interface_configs(R)],
win32reg:close(R),
{TopConfig, Configs}.
pick_config() ->
{TopConfig, Configs} = all_configs(),
NSConfigs = [{If, C} || {If, C} <- Configs,
get_value(["DhcpNameServer","NameServer"], C)
=/= undefined],
case get_value(["DhcpNameServer","NameServer"],
TopConfig) of
%% No top level nameserver to pick interface with
undefined ->
hd(sort_configs(NSConfigs));
%% Top level has a nameserver - use this to select an interface.
NS ->
Cs = [ {If, C}
|| {If, C} <- Configs,
lists:member(NS,
[get_value(["NameServer"], C),
get_value(["DhcpNameServer"], C)])],
hd(sort_configs(Cs))
end.
get_value([], _Config) -> undefined;
get_value([K|Keys], Config) ->
case proplists:get_value(K, Config) of
undefined -> get_value(Keys, Config);
V -> V
end.