summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--net-im/ejabberd/Manifest53
-rw-r--r--net-im/ejabberd/ejabberd-1.1.2-r1.ebuild206
-rw-r--r--net-im/ejabberd/ejabberd-1.1.2-r2.ebuild208
-rw-r--r--net-im/ejabberd/files/check_pam.diff472
-rw-r--r--net-im/ejabberd/files/ejabberd-1.1.2-mod-proxy.patch423
-rw-r--r--net-im/ejabberd/files/ejabberd-1.1.2-statsdx-web.patch318
-rw-r--r--net-im/ejabberd/files/ejabberd-1.1.2-statsdx.patch742
-rw-r--r--net-im/ejabberd/files/ejabberd-1.1.2.initd59
-rw-r--r--net-im/ejabberd/files/http_binding.patch1006
-rw-r--r--net-im/ejabberd/files/mod_archive.erl695
-rw-r--r--net-im/ejabberd/files/mod_irc_utf-8.patch11
-rw-r--r--net-im/ejabberd/files/mod_pep.patch2319
12 files changed, 0 insertions, 6512 deletions
diff --git a/net-im/ejabberd/Manifest b/net-im/ejabberd/Manifest
deleted file mode 100644
index 3638dacc..00000000
--- a/net-im/ejabberd/Manifest
+++ /dev/null
@@ -1,53 +0,0 @@
-AUX check_pam.diff 12905 RMD160 aee968e9d72be0b0cbc37852226db14cba67a4fe SHA1 92fd41da261025f3cb4af056e46db16391d5e6e1 SHA256 d8ec3dd0ff902c465535809a94e7bd3c34bd53c7d0a50a206150e688ac6386c9
-MD5 6b0c111316a61e615be8da892b596266 files/check_pam.diff 12905
-RMD160 aee968e9d72be0b0cbc37852226db14cba67a4fe files/check_pam.diff 12905
-SHA256 d8ec3dd0ff902c465535809a94e7bd3c34bd53c7d0a50a206150e688ac6386c9 files/check_pam.diff 12905
-AUX ejabberd-1.1.2-mod-proxy.patch 14771 RMD160 4a3d817fd103aebfb8e76fc9f23396b57da5f473 SHA1 023ab0fe368bd6de78ad21a977b1d5a09818cab3 SHA256 3c130d4d76fcc6e51014c4ef7db2939d3d6ee911f59fe17bd580ca914a07d6e3
-MD5 c9f267fcc007f5a0a92834fc63d9cb3e files/ejabberd-1.1.2-mod-proxy.patch 14771
-RMD160 4a3d817fd103aebfb8e76fc9f23396b57da5f473 files/ejabberd-1.1.2-mod-proxy.patch 14771
-SHA256 3c130d4d76fcc6e51014c4ef7db2939d3d6ee911f59fe17bd580ca914a07d6e3 files/ejabberd-1.1.2-mod-proxy.patch 14771
-AUX ejabberd-1.1.2-statsdx-web.patch 9287 RMD160 e98789d5b29f6fcb55c383e551239378c8ce3eb6 SHA1 4e35a28d7692ae3d36bd0c5590b482c9f8266309 SHA256 4036facbe4bd712784e5964b1e422b1f3f60aeff8ec1058b3358c45535b4e8d9
-MD5 ae2346c4c0a0540b3236a80a2bf12451 files/ejabberd-1.1.2-statsdx-web.patch 9287
-RMD160 e98789d5b29f6fcb55c383e551239378c8ce3eb6 files/ejabberd-1.1.2-statsdx-web.patch 9287
-SHA256 4036facbe4bd712784e5964b1e422b1f3f60aeff8ec1058b3358c45535b4e8d9 files/ejabberd-1.1.2-statsdx-web.patch 9287
-AUX ejabberd-1.1.2-statsdx.patch 24201 RMD160 e04d36746649e435a68c32f2705a27fc9107009e SHA1 6d621b54addfcdb047ec7b4314573ec4aa161ef9 SHA256 27dfeaa59ab901c9c08d7dca9fc667252cec64fa08d8e43adaa7e72f961f864f
-MD5 a5fc80bf820a7d5ef93354895bd2928a files/ejabberd-1.1.2-statsdx.patch 24201
-RMD160 e04d36746649e435a68c32f2705a27fc9107009e files/ejabberd-1.1.2-statsdx.patch 24201
-SHA256 27dfeaa59ab901c9c08d7dca9fc667252cec64fa08d8e43adaa7e72f961f864f files/ejabberd-1.1.2-statsdx.patch 24201
-AUX ejabberd-1.1.2.initd 1298 RMD160 ec7b25205026521ec09f8595bbe6ae36c94bc55f SHA1 012122c9e930ec56257a625a4fd3bd28e140afd3 SHA256 69481e6f156e85c69038675283f818fe3fa92d0ab442aaf78831345969aa021a
-MD5 13c4ef3cee491a8529dc8866347f0636 files/ejabberd-1.1.2.initd 1298
-RMD160 ec7b25205026521ec09f8595bbe6ae36c94bc55f files/ejabberd-1.1.2.initd 1298
-SHA256 69481e6f156e85c69038675283f818fe3fa92d0ab442aaf78831345969aa021a files/ejabberd-1.1.2.initd 1298
-AUX http_binding.patch 34601 RMD160 ce1305c772e81769d9165eaa00ef75c18ede05ba SHA1 3902127e05612bfe2a57efba54c057a5db911540 SHA256 1a31e631a8bdc25a221ac81a29d5573a671c64ee0cf56cc3e4839bb91fdf6bdd
-MD5 75adcbc43ce318b2c30a5ab09aab21dc files/http_binding.patch 34601
-RMD160 ce1305c772e81769d9165eaa00ef75c18ede05ba files/http_binding.patch 34601
-SHA256 1a31e631a8bdc25a221ac81a29d5573a671c64ee0cf56cc3e4839bb91fdf6bdd files/http_binding.patch 34601
-AUX mod_archive.erl 29560 RMD160 6c628ca4f1d82cd826c2a4d11c87d6b3344f3f24 SHA1 b934e9a9ed1ab7dc700b589177dc9425aa535a6f SHA256 b46976ca86a43cb13ed71009a5fadf7a2ca231e51da83150cdff0d646fbed00f
-MD5 c3c630a783edc22b0d81646f2c2eb829 files/mod_archive.erl 29560
-RMD160 6c628ca4f1d82cd826c2a4d11c87d6b3344f3f24 files/mod_archive.erl 29560
-SHA256 b46976ca86a43cb13ed71009a5fadf7a2ca231e51da83150cdff0d646fbed00f files/mod_archive.erl 29560
-AUX mod_irc_utf-8.patch 376 RMD160 74a370b992810607e6c61995c2e5c31623ce10d6 SHA1 502d263d8407c5137992a25e25a998574796292a SHA256 48f3d0de218de31fced3b6e9bd160981020921dfcf41a4990a0ea84c15802a06
-MD5 6a1fe58a1e40edea5131a7cabc020f73 files/mod_irc_utf-8.patch 376
-RMD160 74a370b992810607e6c61995c2e5c31623ce10d6 files/mod_irc_utf-8.patch 376
-SHA256 48f3d0de218de31fced3b6e9bd160981020921dfcf41a4990a0ea84c15802a06 files/mod_irc_utf-8.patch 376
-AUX mod_pep.patch 74047 RMD160 04ea7221b539038a3610a2d745667abbe4b39969 SHA1 4c072204fc46e928492336dcc587c725e14992b1 SHA256 8335979552f290078015347433b0eb1aaa7f59da8431874b4720cd99f7ef91cf
-MD5 f6f334f668f70146c06dcdfcb55e0f40 files/mod_pep.patch 74047
-RMD160 04ea7221b539038a3610a2d745667abbe4b39969 files/mod_pep.patch 74047
-SHA256 8335979552f290078015347433b0eb1aaa7f59da8431874b4720cd99f7ef91cf files/mod_pep.patch 74047
-DIST ejabberd-1.1.1_httpbind.tar.gz 14496 RMD160 3dd17d39daf0ff58ed6572559dbc74faadc475cc SHA1 82d9c2b63b27d241fc08495347d979fbd000b66f SHA256 a5e48ce27b9691ef428f82959e6d487e6b293b60fbc415cc88a99bed476e720c
-DIST ejabberd-1.1.2.tar.gz 836240 RMD160 e763752e6c5fb46c51b71e265ab2ceda6d043a0d SHA1 9e94bdbc10fee5b781405daf43a0b4abc4dee6c1 SHA256 029129a6bcb5d15dbccc5aa756f61c52692eb6882ec7aad0193aa940b6a20bb6
-DIST mod_presence-0.0.4.tar.gz 51874 RMD160 f9a724b4c6d58fc83c09f71eacb18b6b0ba77ea9 SHA1 c9a7f05939798bdaf61f9ca8da5c0ac80258afbd SHA256 0f3983a61ac779ddbadde94961db0ce724bff2fb23483654d1be0221a13c5a11
-EBUILD ejabberd-1.1.2-r1.ebuild 6047 RMD160 67cac92974a0abad21d0742691541d4e04763ba8 SHA1 c3f5dbd14928e4f3bae8743af7c0ca0a5466fae5 SHA256 8b3a13991e2a1b2a3e9d262acfa663f6e7c054596801e96359121a0e25b15f55
-MD5 97b595d6ef284930fda4e83563e6ef3f ejabberd-1.1.2-r1.ebuild 6047
-RMD160 67cac92974a0abad21d0742691541d4e04763ba8 ejabberd-1.1.2-r1.ebuild 6047
-SHA256 8b3a13991e2a1b2a3e9d262acfa663f6e7c054596801e96359121a0e25b15f55 ejabberd-1.1.2-r1.ebuild 6047
-EBUILD ejabberd-1.1.2-r2.ebuild 6209 RMD160 7a973a37daf3a730f25d241473a31fe7f862900d SHA1 a335c84fffdf2650300e293802036b0f5794974e SHA256 9f24c0974d49c61e6e0cb74485e4f4b557a86ee803a703eb6d6565746e54f57b
-MD5 879774d13f6783428209f434c395d1c8 ejabberd-1.1.2-r2.ebuild 6209
-RMD160 7a973a37daf3a730f25d241473a31fe7f862900d ejabberd-1.1.2-r2.ebuild 6209
-SHA256 9f24c0974d49c61e6e0cb74485e4f4b557a86ee803a703eb6d6565746e54f57b ejabberd-1.1.2-r2.ebuild 6209
-MD5 30a6b40979271475494b8103ac79c2b4 files/digest-ejabberd-1.1.2-r1 497
-RMD160 93a5b27c67cf098e343f1e877df1bdb5b4fe05ff files/digest-ejabberd-1.1.2-r1 497
-SHA256 e90edb5f4836aa10b0e5490f1d9ed4d690c9dbd841ad566e03797f61f41f9024 files/digest-ejabberd-1.1.2-r1 497
-MD5 28991a43f2edef2f12f58b614f87d1a3 files/digest-ejabberd-1.1.2-r2 765
-RMD160 ab10e70d0a76179cfa03d7358b790ca12caa1484 files/digest-ejabberd-1.1.2-r2 765
-SHA256 3fb5d04a5f49ed371b8f835c393ea62c566c669d9ad1557073dbc3a04d11cc82 files/digest-ejabberd-1.1.2-r2 765
diff --git a/net-im/ejabberd/ejabberd-1.1.2-r1.ebuild b/net-im/ejabberd/ejabberd-1.1.2-r1.ebuild
deleted file mode 100644
index 2ba43ad6..00000000
--- a/net-im/ejabberd/ejabberd-1.1.2-r1.ebuild
+++ /dev/null
@@ -1,206 +0,0 @@
-# Copyright 1999-2006 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-# $Header: $
-
-inherit eutils multilib ssl-cert versionator autotools
-
-JABBER_ETC="/etc/jabber"
-JABBER_RUN="/var/run/jabber"
-JABBER_SPOOL="/var/spool/jabber"
-JABBER_LOG="/var/log/jabber"
-
-E_MYSQL_V="5"
-E_MYSQL_N="mysql"
-E_MYSQL=${E_MYSQL_N}-${E_MYSQL_V}
-
-E_PGSQL_V="0.0.1"
-E_PGSQL_N="pgsql-cvs"
-E_PGSQL=${E_PGSQL_N}-${E_PGSQL_V}
-
-DESCRIPTION="The Erlang Jabber Daemon"
-HOMEPAGE="http://ejabberd.jabber.ru/"
-SRC_URI="http://process-one.net/en/projects/${PN}/download/${PV}/${P}.tar.gz
- mod_presence? ( http://www.goryachev.org/jabber/mod_presence-0.0.4.tar.gz )"
-LICENSE="GPL-2"
-SLOT="0"
-KEYWORDS="x86 ~amd64"
-IUSE="${IUSE} mod_archive mod_irc mod_muc mod_pep mod_pubsub mod_presence mod_proxy statsdx ldap odbc pam web mysql postgres http_binding"
-
-DEPEND="${RDEPEND}
- >=net-im/jabber-base-0.01
- >=dev-libs/expat-1.95
- >=dev-lang/erlang-10.2.0
- odbc? ( dev-db/unixODBC )
- ldap? ( =net-nds/openldap-2* )
- postgres? ( =dev-erl/${E_PGSQL} )
- mysql? ( =dev-erl/${E_MYSQL} )
- pam? ( sys-libs/pam)"
-RDEPEND="postgres? ( dev-db/postgresql )
- mysql? ( dev-db/mysql )"
-
-RESTRICT="nomirror"
-
-PROVIDE="virtual/jabber-server"
-S=${WORKDIR}/${P}/src
-
-src_unpack() {
- unpack ${A}
- cd ${S}
-
- MYSQL_P=$(best_version dev-db/mysql)
- MYSQL_PV=${MYSQL_P/dev-db\/mysql-/}
-
- #
- # If we have to work with MySQL 4.1 or greater, ejabberd's native
- # MySQL-driver has to be patched to query "SET NAMES 'utf8'" on connecting
- # the database.
- #
- if use mysql && \
- (( \
- [ $(get_major_version ${MYSQL_PV}) -eq 4 ] && \
- [ $(get_major_version $(get_after_major_version ${MYSQL_PV})) -ge 1] \
- ) \
- || \
- [ $(get_major_version ${MYSQL_PV}) -ge 5 ] \
- ); then
- epatch ${FILESDIR}/${P}-mysql-connect-utf8.patch
- fi
-
- if use statsdx; then
- epatch ${FILESDIR}/${P}-statsdx.patch
- epatch ${FILESDIR}/${P}-statsdx-web.patch
- fi
-
- use pam && epatch ${FILESDIR}/check_pam.diff # http://ejabberd.jabber.ru/pam
- use mod_proxy && epatch ${FILESDIR}/${P}-mod-proxy.patch # http://bugs.gentoo.org/show_bug.cgi?id=137724
- use mod_pep && epatch ${FILESDIR}/mod_pep.patch # http://www.dtek.chalmers.se/~henoch/text/ejabberd-pep.html
- use http_binding && epatch ${FILESDIR}/http_binding.patch # http://www.jabber.ru/bugzilla/show_bug.cgi?id=91 | http://ejabberd.jabber.ru/mod_proxy65
- use mod_archive && cp ${FILESDIR}/mod_archive.erl ${S} # http://ejabberd.jabber.ru/mod_archive
-
- if use mod_presence; then
- cp -r ${WORKDIR}/mod_presence/pixmaps ${S}
- epatch ${WORKDIR}/mod_presence/mod_presence.diff
- fi
-}
-
-src_compile() {
- local myconf
-
- if ! use mysql && ! use postgres && ! use odbc; then
- myconf="--disable-odbc"
- else
- myconf="--enable-odbc"
- fi
-
- eautoconf
- econf ${myconf} \
- --enable-roster-gateway-workaround \
- $(use_enable mod_irc) \
- $(use_enable ldap eldap) \
- $(use_enable mod_muc) \
- $(use_enable mod_pubsub) \
- $(use_enable ssl tls) \
- $(use_enable web) \
- $(use_enable odbc) \
- $(use_enable mod_presence) \
- || die "econf failed"
-
- emake || die "compiling ejabberd core failed"
-}
-
-src_install() {
- make \
- DESTDIR=${D} \
- EJABBERDDIR=${D}/usr/$(get_libdir)/erlang/lib/${P} \
- ETCDIR=${D}${JABBER_ETC} \
- LOGDIR=${D}${JABBER_LOG} \
- install \
- || die "install failed"
-
- insinto /usr/share/doc/${PF}
- use postgres && doins odbc/pg.sql
- use mysql && doins odbc/mysql.sql
- cd ${S}/..
- dodoc doc/release_notes_${PV}.txt
- dohtml doc/*.{html,png}
-
- use postgres && {
- pa="-pa /usr/$(get_libdir)/erlang/lib/${E_PGSQL}/ebin"
- }
-
- use mysql && {
- pa=${pa}" -pa /usr/$(get_libdir)/erlang/lib/${E_MYSQL}/ebin"
- }
-
- #
- # Create /usr/bin/ejabberd
- #
- cat <<EOF > ${T}/ejabberd
-#!/bin/bash
-
-erl -pa /usr/$(get_libdir)/erlang/lib/${P}/ebin \\
- ${pa} \\
- -sname ejabberd \\
- -s ejabberd \\
- -ejabberd config \"${JABBER_ETC}/ejabberd.cfg\" \\
- log_path \"${JABBER_LOG}/ejabberd.log\" \\
- -kernel inetrc \"${JABBER_ETC}/inetrc\" \\
- -sasl sasl_error_logger \{file,\"${JABBER_LOG}/sasl.log\"\} \\
- -mnesia dir \"${JABBER_SPOOL}\" \\
- \$@
-EOF
-
- #
- # Create /usr/bin/ejabberdctl
- #
- cat <<EOF > ${T}/ejabberdctl
-#!/bin/sh
-
-exec env HOME=${JABBER_RUN} \\
- erl -pa /usr/$(get_libdir)/erlang/lib/${P}/ebin \\
- ${pa} \\
- -noinput \\
- -sname ejabberdctl \\
- -s ejabberd_ctl \\
- -extra \$@
-EOF
-
- dobin ${T}/ejabberdctl
- dobin ${T}/ejabberd
-
- newinitd ${FILESDIR}/${P}.initd ${PN}
- newconfd ${FILESDIR}/${P}.confd ${PN}
-
- insinto ${JABBER_ETC}
- if use ssl; then
- docert ssl
- rm -f ${D}${JABBER_ETC}/ssl.{crt,csr,key}
- fowners jabber:jabber ${JABBER_ETC}/ssl.pem
- fi
- doins ${FILESDIR}/inetrc
-}
-
-pkg_postinst() {
- if [ ! -e ${JABBER_ETC}/ejabberd.cfg ]
- then
- einfo "Configuration file has been installed in ${JABBER_ETC}/ejabberd.cfg."
- einfo "Edit it according to your needs. For configuration instructions,"
- einfo "please see /usr/share/doc/${PF}/html/guide.html"
- fi
- if use ssl ; then
- einfo "A script to generate a ssl key has been installed in"
- einfo "${JABBER_ETC}/self-cert.sh . Use it and change the config file to"
- einfo "point to the full path"
- fi
- if ! use web ; then
- einfo "The web USE flag is off, this will disable the web admin interface,"
- einfo "if this was not the intention then add web to your USE flags."
- fi
-
- if use modproxy ; then
- einfo "mod_proxy enabled ! http://www.jabber.ru/bugzilla/show_bug.cgi?id=25"
- fi
- if use statsdx ; then
- einfo "Advanced stats enabled ! http://ejabberd.jabber.ru/mod_statsdx"
- fi
-}
diff --git a/net-im/ejabberd/ejabberd-1.1.2-r2.ebuild b/net-im/ejabberd/ejabberd-1.1.2-r2.ebuild
deleted file mode 100644
index 39ca1373..00000000
--- a/net-im/ejabberd/ejabberd-1.1.2-r2.ebuild
+++ /dev/null
@@ -1,208 +0,0 @@
-# Copyright 1999-2006 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-# $Header: $
-
-inherit eutils multilib ssl-cert versionator autotools
-
-JABBER_ETC="/etc/jabber"
-JABBER_RUN="/var/run/jabber"
-JABBER_SPOOL="/var/spool/jabber"
-JABBER_LOG="/var/log/jabber"
-
-E_MYSQL_V="5"
-E_MYSQL_N="mysql"
-E_MYSQL=${E_MYSQL_N}-${E_MYSQL_V}
-
-E_PGSQL_V="0.0.1"
-E_PGSQL_N="pgsql-cvs"
-E_PGSQL=${E_PGSQL_N}-${E_PGSQL_V}
-
-DESCRIPTION="The Erlang Jabber Daemon"
-HOMEPAGE="http://ejabberd.jabber.ru/"
-SRC_URI="http://process-one.net/en/projects/${PN}/download/${PV}/${P}.tar.gz
- mod_presence? ( http://www.goryachev.org/jabber/mod_presence-0.0.4.tar.gz )
- http_binding? ( http://mabber.com/static/ejabberd-1.1.1_httpbind.tar.gz )"
-LICENSE="GPL-2"
-SLOT="0"
-KEYWORDS="x86 ~amd64"
-IUSE="${IUSE} mod_archive mod_irc mod_muc mod_pep mod_pubsub mod_presence mod_proxy statsdx ldap odbc pam web mysql postgres http_binding"
-
-DEPEND="${RDEPEND}
- >=net-im/jabber-base-0.01
- >=dev-libs/expat-1.95
- >=dev-lang/erlang-10.2.0
- odbc? ( dev-db/unixODBC )
- ldap? ( =net-nds/openldap-2* )
- pam? ( sys-libs/pam)"
-RDEPEND="postgres? ( dev-db/postgresql )
- mysql? ( dev-db/mysql )"
-
-RESTRICT="nomirror"
-
-PROVIDE="virtual/jabber-server"
-S=${WORKDIR}/${P}/src
-
-src_unpack() {
- unpack ${A}
- cd ${S}
-
- MYSQL_P=$(best_version dev-db/mysql)
- MYSQL_PV=${MYSQL_P/dev-db\/mysql-/}
-
- #
- # If we have to work with MySQL 4.1 or greater, ejabberd's native
- # MySQL-driver has to be patched to query "SET NAMES 'utf8'" on connecting
- # the database.
- #
- if use mysql && \
- (( \
- [ $(get_major_version ${MYSQL_PV}) -eq 4 ] && \
- [ $(get_major_version $(get_after_major_version ${MYSQL_PV})) -ge 1] \
- ) \
- || \
- [ $(get_major_version ${MYSQL_PV}) -ge 5 ] \
- ); then
- epatch ${FILESDIR}/${P}-mysql-connect-utf8.patch
- fi
-
- if use statsdx; then
- epatch ${FILESDIR}/${P}-statsdx.patch
- epatch ${FILESDIR}/${P}-statsdx-web.patch
- fi
-
- epatch ${FILESDIR}/mod_irc_utf-8.patch
-
- use pam && epatch ${FILESDIR}/check_pam.diff # http://ejabberd.jabber.ru/pam
- use mod_proxy && epatch ${FILESDIR}/${P}-mod-proxy.patch # http://bugs.gentoo.org/show_bug.cgi?id=137724
- use mod_pep && epatch ${FILESDIR}/mod_pep.patch # http://www.dtek.chalmers.se/~henoch/text/ejabberd-pep.html
- #use http_binding && epatch ${WORKDIR}/ejabberd-1.1.1_httpbind/ejabberd-1.1.1_httpbind.patch.gz # http://blog.mabber.de/eintrag.php?id=34
- use http_binding && ( cd .. ; epatch ${FILESDIR}/http_binding.patch ;) # http://www.jabber.ru/bugzilla/show_bug.cgi?id=91
- use mod_archive && cp ${FILESDIR}/mod_archive.erl ${S} # http://ejabberd.jabber.ru/mod_archive
-
- if use mod_presence; then
- cp -r ${WORKDIR}/mod_presence/pixmaps ${S}
- epatch ${WORKDIR}/mod_presence/mod_presence.diff
- fi
-}
-
-src_compile() {
- local myconf
-
- if ! use mysql && ! use postgres && ! use odbc; then
- myconf="--disable-odbc"
- else
- myconf="--enable-odbc"
- fi
-
- eautoconf
- econf ${myconf} \
- --enable-roster-gateway-workaround \
- $(use_enable mod_irc) \
- $(use_enable ldap eldap) \
- $(use_enable mod_muc) \
- $(use_enable mod_pubsub) \
- $(use_enable ssl tls) \
- $(use_enable web) \
- $(use_enable odbc) \
- $(use_enable mod_presence) \
- || die "econf failed"
-
- emake || die "compiling ejabberd core failed"
-}
-
-src_install() {
- make \
- DESTDIR=${D} \
- EJABBERDDIR=${D}/usr/$(get_libdir)/erlang/lib/${P} \
- ETCDIR=${D}${JABBER_ETC} \
- LOGDIR=${D}${JABBER_LOG} \
- install \
- || die "install failed"
-
- insinto /usr/share/doc/${PF}
- use postgres && doins odbc/pg.sql
- use mysql && doins odbc/mysql.sql
- cd ${S}/..
- dodoc doc/release_notes_${PV}.txt
- dohtml doc/*.{html,png}
-
- use postgres && {
- pa="-pa /usr/$(get_libdir)/erlang/lib/${E_PGSQL}/ebin"
- }
-
- use mysql && {
- pa=${pa}" -pa /usr/$(get_libdir)/erlang/lib/${E_MYSQL}/ebin"
- }
-
- #
- # Create /usr/bin/ejabberd
- #
- cat <<EOF > ${T}/ejabberd
-#!/bin/bash
-
-erl -pa /usr/$(get_libdir)/erlang/lib/${P}/ebin \\
- ${pa} \\
- -sname ejabberd \\
- -s ejabberd \\
- -ejabberd config \"${JABBER_ETC}/ejabberd.cfg\" \\
- log_path \"${JABBER_LOG}/ejabberd.log\" \\
- -kernel inetrc \"${JABBER_ETC}/inetrc\" \\
- -sasl sasl_error_logger \{file,\"${JABBER_LOG}/sasl.log\"\} \\
- -mnesia dir \"${JABBER_SPOOL}\" \\
- \$@
-EOF
-
- #
- # Create /usr/bin/ejabberdctl
- #
- cat <<EOF > ${T}/ejabberdctl
-#!/bin/sh
-
-exec env HOME=${JABBER_RUN} \\
- erl -pa /usr/$(get_libdir)/erlang/lib/${P}/ebin \\
- ${pa} \\
- -noinput \\
- -sname ejabberdctl \\
- -s ejabberd_ctl \\
- -extra \$@
-EOF
-
- dobin ${T}/ejabberdctl
- dobin ${T}/ejabberd
-
- newinitd ${FILESDIR}/${P}.initd ${PN}
- newconfd ${FILESDIR}/${P}.confd ${PN}
-
- insinto ${JABBER_ETC}
- if use ssl; then
- docert ssl
- rm -f ${D}${JABBER_ETC}/ssl.{crt,csr,key}
- fowners jabber:jabber ${JABBER_ETC}/ssl.pem
- fi
- doins ${FILESDIR}/inetrc
-}
-
-pkg_postinst() {
- if [ ! -e ${JABBER_ETC}/ejabberd.cfg ]
- then
- einfo "Configuration file has been installed in ${JABBER_ETC}/ejabberd.cfg."
- einfo "Edit it according to your needs. For configuration instructions,"
- einfo "please see /usr/share/doc/${PF}/html/guide.html"
- fi
- if use ssl ; then
- einfo "A script to generate a ssl key has been installed in"
- einfo "${JABBER_ETC}/self-cert.sh . Use it and change the config file to"
- einfo "point to the full path"
- fi
- if ! use web ; then
- einfo "The web USE flag is off, this will disable the web admin interface,"
- einfo "if this was not the intention then add web to your USE flags."
- fi
-
- if use modproxy ; then
- einfo "mod_proxy enabled ! http://www.jabber.ru/bugzilla/show_bug.cgi?id=25"
- fi
- if use statsdx ; then
- einfo "Advanced stats enabled ! http://ejabberd.jabber.ru/mod_statsdx"
- fi
-}
diff --git a/net-im/ejabberd/files/check_pam.diff b/net-im/ejabberd/files/check_pam.diff
deleted file mode 100644
index b03a8803..00000000
--- a/net-im/ejabberd/files/check_pam.diff
+++ /dev/null
@@ -1,472 +0,0 @@
-Index: Makefile.in
-===================================================================
---- Makefile.in (revisión: 626)
-+++ Makefile.in (copia de trabajo)
-@@ -27,7 +27,7 @@
-
- prefix = @prefix@
-
--SUBDIRS = @mod_irc@ @mod_pubsub@ @mod_muc@ @eldap@ @web@ stringprep @tls@ @odbc@ @ejabberd_zlib@
-+SUBDIRS = @mod_irc@ @mod_pubsub@ @mod_muc@ @eldap@ @web@ stringprep @tls@ @odbc@ @ejabberd_zlib@ @pam@
- ERLSHLIBS = expat_erl.so
- SOURCES = $(wildcard *.erl)
- BEAMS = $(SOURCES:.erl=.beam)
-Index: configure.ac
-===================================================================
---- configure.ac (revisión: 626)
-+++ configure.ac (copia de trabajo)
-@@ -16,6 +16,8 @@
- AM_WITH_EXPAT
- #locating zlib
- AM_WITH_ZLIB
-+#locating zlib
-+AM_WITH_ZLIB
-
- # Checks for typedefs, structures, and compiler characteristics.
- AC_C_CONST
-@@ -27,6 +29,7 @@
- AC_FUNC_MALLOC
- AC_HEADER_STDC
-
-+AC_MOD_ENABLE(pam, yes)
- AC_MOD_ENABLE(mod_pubsub, yes)
- AC_MOD_ENABLE(mod_irc, yes)
- AC_MOD_ENABLE(mod_muc, yes)
-@@ -55,6 +58,7 @@
- AC_SUBST(db_type)
-
- AC_CONFIG_FILES([Makefile
-+ $make_pam
- $make_mod_irc
- $make_mod_muc
- $make_mod_pubsub
-Index: pam/stress_pam.erl
-===================================================================
---- pam/stress_pam.erl (revisión: 0)
-+++ pam/stress_pam.erl (revisión: 0)
-@@ -0,0 +1,11 @@
-+-module(stress_pam).
-+-export([start/0]).
-+
-+start() ->
-+ Port = pam:start(),
-+ stress(Port).
-+
-+stress(Port) ->
-+ true = pam:check_password(Port, "user", "password"),
-+ timer:sleep(200),
-+ stress(Port).
-Index: pam/Makefile.in
-===================================================================
---- pam/Makefile.in (revisión: 0)
-+++ pam/Makefile.in (revisión: 0)
-@@ -0,0 +1,35 @@
-+# $Id: Makefile.in 285 2004-11-05 21:14:31Z aleksey $
-+
-+CC = @CC@
-+CFLAGS = @CFLAGS@ @PAM_CFLAGS@ @ERLANG_CFLAGS@
-+CPPFLAGS = @CPPFLAGS@
-+LDFLAGS = @LDFLAGS@
-+LIBS = @LIBS@ @PAM_LIBS@ @ERLANG_LIBS@
-+
-+SUBDIRS =
-+
-+ERLSHLIBS = ../pam_drv.so
-+
-+OUTDIR = ..
-+EFLAGS = -I .. -pz ..
-+OBJS = \
-+ $(OUTDIR)/pam.beam
-+
-+all: $(OBJS) $(ERLSHLIBS)
-+
-+$(OUTDIR)/%.beam: %.erl
-+ @ERLC@ -W $(EFLAGS) -o $(OUTDIR) $<
-+
-+$(ERLSHLIBS): ../%.so: %.c
-+ $(CC) -Wall $(CFLAGS) $(LDFLAGS) \
-+ $(subst ../,,$(subst .so,.c,$@)) $(LIBS) \
-+ -o $@ -fpic -shared
-+
-+clean:
-+ rm -f $(OBJS) $(ERLSHLIBS)
-+
-+distclean: clean
-+ rm -f Makefile
-+
-+TAGS:
-+ etags *.erl
-Index: pam/pam_drv.c
-===================================================================
---- pam/pam_drv.c (revisión: 0)
-+++ pam/pam_drv.c (revisión: 0)
-@@ -0,0 +1,235 @@
-+#include <stdio.h>
-+#include <string.h>
-+#include <erl_driver.h>
-+#include <ei.h>
-+#include <security/pam_appl.h>
-+
-+typedef struct _PromptMatch
-+{
-+ struct _PromptMatch* next;
-+ char* prompt;
-+ char* response;
-+} *PromptMatch;
-+
-+static PromptMatch _newMatch(PromptMatch list, char* prompt, char* response)
-+{
-+ PromptMatch result = (PromptMatch)malloc(sizeof(struct _PromptMatch));
-+ memset(result, '\0', sizeof(struct _PromptMatch));
-+ result->prompt = prompt;
-+ result->response = response;
-+ if (list != NULL)
-+ {
-+ list->next = result;
-+ return list;
-+ }
-+ else
-+ {
-+ return result;
-+ }
-+}
-+
-+static char* _findMatch(PromptMatch list, const char* prompt)
-+{
-+ PromptMatch cur = list;
-+ while (cur != NULL)
-+ {
-+ if (strstr(prompt, cur->prompt) != 0)
-+ {
-+ return cur->response;
-+ }
-+ cur = cur->next;
-+ }
-+ return NULL;
-+}
-+
-+static void _cleanupMatch(PromptMatch list)
-+{
-+ PromptMatch cur = list;
-+ PromptMatch next;
-+ while (cur != NULL)
-+ {
-+ free(cur->prompt);
-+ free(cur->response);
-+ next = cur->next;
-+ free(cur);
-+ cur = next;
-+ }
-+}
-+
-+static int _handle_pam_conversation(int msgcnt, const struct pam_message** msgs, struct pam_response** res,
-+ void* arg)
-+{
-+ int i;
-+ PromptMatch prompts = (PromptMatch)arg;
-+ struct pam_response *reply;
-+
-+ if(msgcnt <= 0)
-+ {
-+ return PAM_CONV_ERR;
-+ }
-+
-+ // Allocate a response for each message
-+ reply = (struct pam_response *) malloc(sizeof(struct pam_response) * msgcnt);
-+ memset(reply, 0, sizeof(struct pam_response) * msgcnt);
-+
-+ // Walk each message from PAM and lookup the response corresponding to each prompt
-+ for(i = 0; i < msgcnt; i++)
-+ {
-+ if(msgs[i]->msg_style == PAM_PROMPT_ECHO_OFF || msgs[i]->msg_style == PAM_PROMPT_ECHO_ON)
-+ {
-+ // Find the response for the current prompt; if none is found, warn
-+ char* response = _findMatch(prompts, msgs[i]->msg);
-+ if (response != NULL)
-+ {
-+ // Copy password into response
-+ reply[i].resp = strdup(response);
-+ reply[i].resp_retcode = 0;
-+ }
-+ else
-+ {
-+ printf("Warning: No prompt found for: %s\n", msgs[i]->msg);
-+ reply[i].resp = strdup("Unexpected prompt");
-+ reply[i].resp_retcode = 0;
-+ }
-+ }
-+ }
-+
-+ *res = reply;
-+
-+ return PAM_SUCCESS;
-+}
-+
-+#define DECODE_STRING(buffer, index, result) \
-+ { \
-+ int tmp = 0; int size = 0; \
-+ ei_get_type(buffer, index, &tmp, &size); \
-+ result = malloc(size + 1); \
-+ ei_decode_string(buffer, index, result); \
-+ }
-+
-+#define RETURN_INT(value) \
-+ { \
-+ ErlDrvBinary* b = driver_alloc_binary(1); \
-+ rlen = 1; \
-+ b->orig_bytes[0] = value; \
-+ *rbuf = (char*)b; \
-+ return rlen; \
-+ }
-+
-+static int pam_erl_start(ErlDrvPort port, char* command)
-+{
-+ set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY);
-+ return 0;
-+}
-+
-+static int pam_erl_control(ErlDrvData drv_data, unsigned int command,
-+ char *buf, int len,
-+ char **rbuf, int rlen)
-+{
-+ int tmp = 0;
-+ int index = 0;
-+ int size = 0;
-+ char* username = 0;
-+ char* password = 0;
-+
-+ int i = 0;
-+ int rc = 0;
-+ struct pam_conv conv;
-+ pam_handle_t* pam;
-+
-+ // Parse the version and tuple header
-+ ei_decode_version(buf, &index, &tmp);
-+ ei_decode_tuple_header(buf, &index, &tmp);
-+ if (tmp != 2)
-+ {
-+ printf("Incorrect number of arguments!\n");
-+ RETURN_INT(-1);
-+ }
-+
-+ // The first item in the tuple should be the username
-+ DECODE_STRING(buf, &index, username);
-+
-+ // The second item in the tuple should be a list of tuples
-+ // Each tuple in the list consists of the expected prompt string
-+ // and the value to return at that prompt
-+ ei_decode_list_header(buf, &index, &size);
-+
-+ // Loop over the list and pull out each prompt/response tuple and
-+ // store it into a PromptItem list that will get processed in
-+ // the PAM conversation
-+ PromptMatch head = NULL;
-+ for (i = 0; i < size; i++)
-+ {
-+ int tuplecnt = 0;
-+ char* prompt = 0;
-+ char* response = 0;
-+
-+ ei_decode_tuple_header(buf, &index, &tuplecnt);
-+ if (tuplecnt != 2)
-+ {
-+ printf("Incorrect number of arguments in prompt/response tuple: %d\n", tuplecnt);
-+ _cleanupMatch(head);
-+ free(username);
-+ RETURN_INT(-2);
-+ }
-+
-+ // Decode the prompt from the tuple
-+ DECODE_STRING(buf, &index, prompt);
-+ DECODE_STRING(buf, &index, response);
-+
-+ // Add a new prompt item to track this prompt/response pair
-+ head = _newMatch(head, prompt, response);
-+ }
-+
-+ // Setup PAM conversation structure; pass in the prompt match list
-+ // so we can process the prompts from PAM
-+ conv.conv = _handle_pam_conversation;
-+ conv.appdata_ptr = head;
-+
-+ // Spin up PAM
-+ rc = pam_start("login", username, &conv, &pam);
-+ if (rc != PAM_SUCCESS)
-+ {
-+ printf("Unable to spin up PAM: %s\n", pam_strerror(NULL, rc));
-+ RETURN_INT(-3);
-+ }
-+
-+ // Attempt to authenticate the user
-+ rc = pam_authenticate(pam, 0);
-+ if (rc != PAM_SUCCESS)
-+ {
-+ pam_end(pam, rc);
-+ printf("Authentication failed for: %s. Error: %s\n", username, pam_strerror(NULL, rc));
-+ free(password);
-+ free(username);
-+ RETURN_INT(1);
-+ }
-+
-+ pam_end(pam, rc);
-+
-+ _cleanupMatch(head);
-+ free(username);
-+
-+ RETURN_INT(0);
-+}
-+
-+ErlDrvEntry pam_driver_entry = {
-+ NULL, /* F_PTR init, N/A */
-+ pam_erl_start, /* L_PTR start, called when port is opened */
-+ NULL, /* F_PTR stop, called when port is closed */
-+ NULL, /* F_PTR output, called when erlang has sent */
-+ NULL, /* F_PTR ready_input, called when input descriptor ready */
-+ NULL, /* F_PTR ready_output, called when
-+ output descriptor ready */
-+ "pam_drv", /* char *driver_name, the argument to open_port */
-+ NULL, /* F_PTR finish, called when unloaded */
-+ NULL, /* handle */
-+ pam_erl_control, /* F_PTR control, port_command callback */
-+ NULL, /* F_PTR timeout, reserved */
-+ NULL /* F_PTR outputv, reserved */
-+};
-+
-+DRIVER_INIT(pam_drv) /* must match name in driver_entry */
-+{
-+ return &pam_driver_entry;
-+}
-Index: pam/pam_test.c
-===================================================================
---- pam/pam_test.c (revisión: 0)
-+++ pam/pam_test.c (revisión: 0)
-@@ -0,0 +1,68 @@
-+#include <stdio.h>
-+#include <string.h>
-+#include <security/pam_appl.h>
-+
-+static int _handle_pam_conversation(int msgcnt, const struct pam_message** msgs, struct pam_response** res,
-+ void* arg)
-+{
-+ int i;
-+ struct pam_response *reply;
-+
-+ if(msgcnt <= 0)
-+ {
-+ return PAM_CONV_ERR;
-+ }
-+
-+ // Allocate a response for each message
-+ reply = (struct pam_response *) malloc(sizeof(struct pam_response) * msgcnt);
-+ memset(reply, 0, sizeof(struct pam_response) * msgcnt);
-+
-+ // Walk each message from PAM and lookup the response corresponding to each prompt
-+ for(i = 0; i < msgcnt; i++)
-+ {
-+ printf("PAM Message(%d): %s\n", msgs[i]->msg_style, msgs[i]->msg);
-+ reply[i].resp = strdup("Unexpected prompt");
-+ reply[i].resp_retcode = 0;
-+ }
-+
-+ *res = reply;
-+
-+ return PAM_SUCCESS;
-+}
-+
-+
-+int main(int args, char** argv)
-+{
-+ struct pam_conv conv;
-+ pam_handle_t* pam;
-+ int rc;
-+
-+ if (args < 3)
-+ {
-+ printf("Please provide a username and service as the first and second arguments!\n");
-+ return -1;
-+ }
-+
-+ char* username = argv[1];
-+ char* service = argv[2];
-+
-+ // Setup PAM conversation structure; pass in the prompt match list
-+ // so we can process the prompts from PAM
-+ conv.conv = _handle_pam_conversation;
-+ conv.appdata_ptr = 0;
-+
-+ // Spin up PAM
-+ rc = pam_start(service, username, &conv, &pam);
-+ if (rc != PAM_SUCCESS)
-+ {
-+ printf("Unable to spin up PAM: %s\n", pam_strerror(NULL, rc));
-+ return -3;
-+ }
-+
-+ // Attempt to authenticate the user
-+ rc = pam_authenticate(pam, 0);
-+
-+ pam_end(pam, rc);
-+
-+ return 0;
-+}
-Index: pam/pam.erl
-===================================================================
---- pam/pam.erl (revisión: 0)
-+++ pam/pam.erl (revisión: 0)
-@@ -0,0 +1,19 @@
-+-module(pam).
-+-author('dizzyd@dizzyd.com').
-+
-+-export([start/0,
-+ check_password/3]).
-+
-+start() ->
-+ ok = erl_ddll:load_driver(ejabberd:get_so_path(), pam_drv),
-+ open_port({spawn, pam_drv}, [binary]).
-+
-+check_password(Port, Username, Password) ->
-+ Bin = term_to_binary({Username, [{"Password:", Password}]}),
-+ Res = port_control(Port, 0, Bin),
-+ case Res of
-+ <<0>> ->
-+ true;
-+ _ ->
-+ false
-+ end.
-Index: aclocal.m4
-===================================================================
---- aclocal.m4 (revisión: 626)
-+++ aclocal.m4 (copia de trabajo)
-@@ -292,3 +292,32 @@
- fi
- ])
- dnl <openssl/>
-+
-+AC_DEFUN(AM_WITH_PAM,
-+[ AC_ARG_WITH(pam, [ --with-pam=PREFIX prefix where PAM is installed ])
-+unset PAM_LIBS;
-+unset PAM_CFLAGS;
-+
-+if test x"$with_pam" != x; then
-+ PAM_CFLAGS="-I$with_pam/include"
-+ PAM_LIBS="-L$with_pam/lib"
-+fi
-+
-+AC_CHECK_LIB(pam, pam_start,
-+ [ PAM_LIBS="$PAM_LIBS -lpam" pam_found=yes ],
-+ [ pam_found=no ],
-+ "$PAM_LIBS")
-+
-+if test $pam_found = yes; then
-+ pam_save_CFLAGS="$CFLAGS"
-+ CFLAGS="$PAM_CFLAGS $CFLAGS"
-+ AC_CHECK_HEADERS(security/pam_appl.h, ,$pam_found=no)
-+ if test $pam_found = no; then
-+ AC_MSG_ERROR([Could not find security/pam_appl.h])
-+ fi
-+ CFLAGS=$pam_save_CFLAGS
-+
-+ AC_SUBST(PAM_CFLAGS)
-+ AC_SUBST(PAM_LIBS)
-+fi
-+])
diff --git a/net-im/ejabberd/files/ejabberd-1.1.2-mod-proxy.patch b/net-im/ejabberd/files/ejabberd-1.1.2-mod-proxy.patch
deleted file mode 100644
index 1981aee1..00000000
--- a/net-im/ejabberd/files/ejabberd-1.1.2-mod-proxy.patch
+++ /dev/null
@@ -1,423 +0,0 @@
-diff -Naur ejabberd-1.1.1/src/ejabberd.cfg.example ejabberd-1.1.1-r1/src/ejabberd.cfg.example
---- ejabberd-1.1.1/src/ejabberd.cfg.example 2006-04-22 15:50:30.000000000 +0200
-+++ ejabberd-1.1.1-r1/src/ejabberd.cfg.example 2006-06-23 09:38:17.000000000 +0200
-@@ -125,6 +125,7 @@
- {max_stanza_size, 131072}
- ]},
- {5280, ejabberd_http, [http_poll, web_admin]},
-+ %{7777, proxy65_listener, [{shaper, c2s_shaper}]},
- {8888, ejabberd_service, [{access, all},
- {hosts, ["icq.localhost", "sms.localhost"],
- [{password, "secret"}]}]}
-@@ -171,6 +172,11 @@
- {mod_pubsub, []},
- {mod_time, []},
- {mod_last, []},
-+ %% Simple configuration (hostname:7777)
-+ %%{mod_proxy65, []},
-+ %% Several possible hostnames
-+ %%{mod_proxy65, [{access, all},
-+ %% {streamhosts, [{"example.com", 7777}, {"192.168.0.42", 7777}]}]},
- {mod_version, []}
- ]}.
-
-diff -Naur ejabberd-1.1.1/src/jlib.hrl ejabberd-1.1.1-r1/src/jlib.hrl
---- ejabberd-1.1.1/src/jlib.hrl 2006-01-20 17:21:39.000000000 +0100
-+++ ejabberd-1.1.1-r1/src/jlib.hrl 2006-06-23 09:38:17.000000000 +0200
-@@ -34,6 +34,7 @@
- -define(NS_PUBSUB_OWNER, "http://jabber.org/protocol/pubsub#owner").
- -define(NS_PUBSUB_NMI, "http://jabber.org/protocol/pubsub#node-meta-info").
- -define(NS_COMMANDS, "http://jabber.org/protocol/commands").
-+-define(NS_BYTESTREAMS, "http://jabber.org/protocol/bytestreams").
-
- -define(NS_EJABBERD_CONFIG, "ejabberd:config").
-
-diff -Naur ejabberd-1.1.1/src/mod_proxy65.erl ejabberd-1.1.1-r1/src/mod_proxy65.erl
---- ejabberd-1.1.1/src/mod_proxy65.erl 1970-01-01 01:00:00.000000000 +0100
-+++ ejabberd-1.1.1-r1/src/mod_proxy65.erl 2006-06-23 09:38:17.000000000 +0200
-@@ -0,0 +1,189 @@
-+%%%----------------------------------------------------------------------
-+%%% File : mod_proxy65.erl
-+%%% Author : Magnus Henoch <henoch@dtek.chalmers.se>
-+%%% Purpose : Handle Jabber communications for JEP-0065 proxy
-+%%% Created : 27 Dec 2005 by Magnus Henoch <henoch@dtek.chalmers.se>
-+%%% Id : $Id: ejabberd_c2s.erl 440 2005-11-22 18:00:56Z alexey $
-+%%%----------------------------------------------------------------------
-+
-+-module(mod_proxy65).
-+-author('henoch@dtek.chalmers.se').
-+-vsn('$Revision$ ').
-+
-+-behaviour(gen_mod).
-+
-+-export([start/2,
-+ init/1,
-+ stop/1]).
-+
-+-include("ejabberd.hrl").
-+-include("jlib.hrl").
-+
-+-record(proxy65_connection, {cookie, firstpid = none, secondpid = none}).
-+
-+-record(proxy65_options, {host, access, streamhosts}).
-+
-+-define(PROCNAME, ejabberd_mod_proxy65).
-+
-+start(Host, Opts) ->
-+ mnesia:create_table(proxy65_connection,
-+ [{ram_copies, [node()]},
-+ {attributes, record_info(fields, proxy65_connection)}]),
-+ MyHost = gen_mod:get_opt(host, Opts, "proxy." ++ Host),
-+ Access = gen_mod:get_opt(access, Opts, all),
-+ Streamhosts = gen_mod:get_opt(streamhosts, Opts, [{Host, 7777}]),
-+
-+ register(gen_mod:get_module_proc(Host, ?PROCNAME),
-+ spawn(?MODULE, init, [#proxy65_options{host = MyHost, access = Access,
-+ streamhosts = Streamhosts}])).
-+
-+
-+stop(Host) ->
-+ Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
-+ Proc ! stop,
-+ {wait, Proc}.
-+
-+init(#proxy65_options{host = Host} = Opts) ->
-+ ejabberd_router:register_route(Host),
-+ loop(Opts).
-+
-+loop(#proxy65_options{host = Host} = Opts) ->
-+ receive
-+ {route, From, To, Packet} ->
-+ case catch do_route(Opts, From, To, Packet) of
-+ {'EXIT', Reason} ->
-+ ?ERROR_MSG("~p", [Reason]);
-+ _ ->
-+ ok
-+ end,
-+ loop(Opts);
-+ stop ->
-+ ejabberd_router:unregister_route(Host),
-+ ok;
-+ _ ->
-+ loop(Opts)
-+ end.
-+
-+do_route(#proxy65_options{host = Host, access = Access} = Opts,
-+ From, To, Packet) ->
-+ case acl:match_rule(Host, Access, From) of
-+ allow ->
-+ do_route1(Opts, From, To, Packet);
-+ _ ->
-+ {xmlelement, _Name, Attrs, _Els} = Packet,
-+ Lang = xml:get_attr_s("xml:lang", Attrs),
-+ ErrText = "Access denied by service policy",
-+ Err = jlib:make_error_reply(Packet,
-+ ?ERRT_FORBIDDEN(Lang, ErrText)),
-+ ejabberd_router:route(To, From, Err)
-+ end.
-+
-+do_route1(#proxy65_options{host = Host, streamhosts = Streamhosts}, From, To, Packet) ->
-+ {xmlelement, Name, _Attrs, _Els} = Packet,
-+ case Name of
-+ "iq" ->
-+ case jlib:iq_query_info(Packet) of
-+ #iq{type = get, xmlns = ?NS_DISCO_INFO = XMLNS,
-+ lang = Lang, sub_el = SubEl} = IQ ->
-+ Node = xml:get_tag_attr_s("node", SubEl),
-+ if Node == [] ->
-+ Res = IQ#iq{type = result,
-+ sub_el = [{xmlelement, "query",
-+ [{"xmlns", XMLNS}],
-+ [{xmlelement, "identity",
-+ [{"category", "proxy"},
-+ {"type", "bytestreams"},
-+ {"name", translate:translate(Lang, "SOCKS5 bytestreams proxy")}],
-+ []},
-+ {xmlelement, "feature",
-+ [{"var", ?NS_BYTESTREAMS}], []}]}]};
-+ true ->
-+ Res = jlib:make_error_reply(Packet, ?ERR_ITEM_NOT_FOUND)
-+ end;
-+ #iq{type = get, xmlns = ?NS_DISCO_ITEMS = XMLNS} = IQ ->
-+ Res = IQ#iq{type = result,
-+ sub_el = [{xmlelement, "query",
-+ [{"xmlns", XMLNS}], []}]};
-+ #iq{type = get, xmlns = ?NS_VERSION} = IQ ->
-+ OSType = case os:type() of
-+ {Osfamily, Osname} ->
-+ atom_to_list(Osfamily) ++ "/" ++
-+ atom_to_list(Osname);
-+ Osfamily ->
-+ atom_to_list(Osfamily)
-+ end,
-+ OSVersion = case os:version() of
-+ {Major, Minor, Release} ->
-+ lists:flatten(
-+ io_lib:format("~w.~w.~w",
-+ [Major, Minor, Release]));
-+ VersionString ->
-+ VersionString
-+ end,
-+ OS = OSType ++ " " ++ OSVersion,
-+ Res = IQ#iq{type = result,
-+ sub_el = [{xmlelement, "query",
-+ [{"xmlns", ?NS_VERSION}],
-+ [{xmlelement, "name", [],
-+ [{xmlcdata, "ejabberd mod_proxy65 (unofficial)"}]},
-+ {xmlelement, "version", [],
-+ [{xmlcdata, "0.1"}]},
-+ {xmlelement, "os", [],
-+ [{xmlcdata, OS}]}
-+ ]}]};
-+ #iq{type = get, xmlns = ?NS_BYTESTREAMS = XMLNS} = IQ ->
-+ Res = IQ#iq{type = result,
-+ sub_el = [{xmlelement, "query",
-+ [{"xmlns", XMLNS}],
-+ return_streamhosts(Host, Streamhosts)}]};
-+ #iq{type = set, xmlns = ?NS_BYTESTREAMS} = IQ ->
-+ Res = activate(Packet, From, To, IQ);
-+ _ ->
-+ Res = jlib:make_error_reply(Packet, ?ERR_FEATURE_NOT_IMPLEMENTED)
-+ end,
-+ case Res of
-+ #iq{} ->
-+ ejabberd_router:route(To, From, jlib:iq_to_xml(Res));
-+ _ ->
-+ ejabberd_router:route(To, From, Res)
-+ end;
-+ _ ->
-+ ejabberd_router:route(To, From, jlib:make_error_reply(Packet, ?ERR_FEATURE_NOT_IMPLEMENTED))
-+ end.
-+
-+return_streamhosts(_JID, []) ->
-+ [];
-+return_streamhosts(JID, [{Host, Port} | Streamhosts]) ->
-+ %% This is not tail-recursive, but it doesn't matter.
-+ [{xmlelement, "streamhost",
-+ [{"jid", JID},
-+ {"host", Host},
-+ {"port", integer_to_list(Port)}],
-+ []} | return_streamhosts(JID, Streamhosts)].
-+
-+activate(Packet, From, _To, #iq{sub_el = SubEl} = IQ) ->
-+ case SubEl of
-+ {xmlelement, "query", Attrs, _SubEls} ->
-+ Sid = xml:get_attr_s("sid", Attrs),
-+ ActivateTag = xml:get_subtag(SubEl, "activate"),
-+ if ActivateTag /= false ->
-+ TargetJID = jlib:string_to_jid(xml:get_tag_cdata(ActivateTag));
-+ true ->
-+ TargetJID = false
-+ end,
-+
-+ if Sid /= [], TargetJID /= false, TargetJID /= error ->
-+ case proxy65_listener:activate(From, TargetJID, Sid) of
-+ ok ->
-+ ?INFO_MSG("Activated connection between ~s and ~s",
-+ [jlib:jid_to_string(From), TargetJID]),
-+ IQ#iq{type = result, sub_el = []};
-+ _ ->
-+ jlib:make_error_reply(Packet, ?ERR_INTERNAL_SERVER_ERROR)
-+ end;
-+ true ->
-+ jlib:make_error_reply(Packet, ?ERR_BAD_REQUEST)
-+ end;
-+ _ ->
-+ jlib:make_error_reply(Packet, ?ERR_BAD_REQUEST)
-+ end.
-diff -Naur ejabberd-1.1.1/src/proxy65_listener.erl ejabberd-1.1.1-r1/src/proxy65_listener.erl
---- ejabberd-1.1.1/src/proxy65_listener.erl 1970-01-01 01:00:00.000000000 +0100
-+++ ejabberd-1.1.1-r1/src/proxy65_listener.erl 2006-06-23 09:38:17.000000000 +0200
-@@ -0,0 +1,192 @@
-+%%%----------------------------------------------------------------------
-+%%% File : proxy65_listener.erl
-+%%% Author : Magnus Henoch <henoch@dtek.chalmers.se>
-+%%% Purpose : Handle SOCKS5 connections for JEP-0065 proxy
-+%%% Created : 27 Dec 2005 by Magnus Henoch <henoch@dtek.chalmers.se>
-+%%% Id : $Id: ejabberd_c2s.erl 440 2005-11-22 18:00:56Z alexey $
-+%%%----------------------------------------------------------------------
-+
-+-module(proxy65_listener).
-+-author('henoch@dtek.chalmers.se').
-+-vsn('$Revision$ ').
-+
-+-export([start/2, handle_connection/2, activate/3]).
-+
-+-include("ejabberd.hrl").
-+-include("jlib.hrl").
-+
-+-record(proxy65_connection, {cookie, firstpid = none, secondpid = none}).
-+
-+start({SockMod, Socket}, Opts) ->
-+ {ok, proc_lib:spawn(?MODULE, handle_connection, [{SockMod, Socket}, Opts])}.
-+
-+read_bytes(_SockOpts, 0, Data) ->
-+ lists:flatten(Data);
-+read_bytes({SockMod, Socket} = SockOpts, N, Data) ->
-+ Timeout = 1000,
-+ case SockMod:recv(Socket, N, Timeout) of
-+ {error, closed} ->
-+ %% On closed connection, return everything we have,
-+ %% but not if we have nothing.
-+ if Data == [] ->
-+ erlang:error(closed);
-+ true ->
-+ lists:flatten(Data)
-+ end;
-+ {ok, MoreData} ->
-+ ?DEBUG("read ~p", [MoreData]),
-+ DataList = binary_to_list(MoreData),
-+ read_bytes(SockOpts, N - length(DataList), [Data, DataList])
-+ end.
-+
-+handle_connection({SockMod, Socket}, Opts) ->
-+ ?DEBUG("in handle_connection", []),
-+ case catch handle_auth({SockMod, Socket}, Opts) of
-+ {'EXIT', Reason} ->
-+ ?ERROR_MSG("~p abnormal termination:~n\t~p~n",
-+ [?MODULE, Reason]),
-+ SockMod:close(Socket);
-+ _ ->
-+ ok
-+ end.
-+
-+handle_auth({SockMod, Socket} = SockOpts, Opts) ->
-+ ?DEBUG("in handle_auth", []),
-+ %% SOCKS protocol stuff...
-+ [5, NAuthMethods] = read_bytes(SockOpts, 2, []),
-+ AuthMethods = read_bytes(SockOpts, NAuthMethods, []),
-+ SupportsNoAuth = lists:member(0, AuthMethods),
-+
-+ %% Must support no authentication, otherwise crash
-+ true = SupportsNoAuth,
-+
-+ SockMod:send(Socket, [5, 0]),
-+
-+ %% And done.
-+ handle_connect(SockOpts, Opts).
-+
-+handle_connect({SockMod, Socket} = SockOpts, Opts) ->
-+ ?DEBUG("in handle_connect", []),
-+ %% Expect a CONNECT command and nothing else
-+ [5, 1, _, 3, AddressLength] = read_bytes(SockOpts, 5, []),
-+ Cookie = read_bytes(SockOpts, AddressLength, []),
-+ [0, 0] = read_bytes(SockOpts, 2, []),
-+
-+ %% Make sure no more than two connections claim the same cookie.
-+ F = fun() ->
-+ case mnesia:read({proxy65_connection, Cookie}) of
-+ [] ->
-+ mnesia:write(#proxy65_connection{cookie = Cookie,
-+ firstpid = self()}),
-+ ok;
-+ [#proxy65_connection{secondpid = none} = C] ->
-+ mnesia:write(C#proxy65_connection{secondpid = self()}),
-+ ok
-+ end
-+ end,
-+
-+ case mnesia:transaction(F) of
-+ {atomic, ok} ->
-+ SockMod:send(Socket, [5, 0, 0, 3, AddressLength, Cookie, 0, 0]),
-+ wait_for_activation(SockOpts, Opts);
-+ Error ->
-+ %% conflict. send "general SOCKS server failure".
-+ SockMod:send(Socket, [5, 1, 0, 3, AddressLength, Cookie, 0, 0]),
-+ erlang:error({badconnect, Error})
-+ end.
-+
-+wait_for_activation(SockOpts, Opts) ->
-+ ?DEBUG("in wait_for_activation", []),
-+ receive
-+ {get_socket, ReplyTo} ->
-+ ReplyTo ! SockOpts,
-+ wait_for_activation(SockOpts, Opts);
-+ {activate, TargetSocket, Initiator, Target} ->
-+ ?DEBUG("activated", []),
-+
-+ %% We have no way of knowing which connection belongs to
-+ %% which participant, so give both the maximum traffic
-+ %% allowed to either.
-+ Shapers = case lists:keysearch(shaper, 1, Opts) of
-+ {value, {_, S}} -> S;
-+ _ -> none
-+ end,
-+ ?DEBUG("we have shapers: ~p", [Shapers]),
-+ Shaper1 = acl:match_rule(global, Shapers, jlib:string_to_jid(Initiator)),
-+ Shaper2 = acl:match_rule(global, Shapers, jlib:string_to_jid(Target)),
-+ if Shaper1 == none; Shaper2 == none ->
-+ MaxShaper = none;
-+ true ->
-+ ShaperValue1 = ejabberd_config:get_global_option({shaper, Shaper1}),
-+ ShaperValue2 = ejabberd_config:get_global_option({shaper, Shaper2}),
-+
-+ if ShaperValue1 > ShaperValue2 ->
-+ MaxShaper = Shaper1;
-+ true ->
-+ MaxShaper = Shaper2
-+ end,
-+ ?DEBUG("shapers have values ~p and ~p~nusing ~p", [ShaperValue1, ShaperValue2, MaxShaper]),
-+ ok
-+ end,
-+
-+ transfer_data(SockOpts, TargetSocket, shaper:new(MaxShaper))
-+ end.
-+
-+transfer_data({SockMod, Socket} = SockOpts, {TargetSockMod, TargetSocket} = TargetSockOpts,
-+ Shaper) ->
-+ case SockMod:recv(Socket, 0, infinity) of
-+ {ok, Data} ->
-+ if Data /= <<>> ->
-+ NewShaper = case Shaper of
-+ none -> none;
-+ _ ->
-+ shaper:update(Shaper, size(Data))
-+ end,
-+ ok = TargetSockMod:send(TargetSocket, Data);
-+ true ->
-+ NewShaper = Shaper
-+ end,
-+ transfer_data(SockOpts, TargetSockOpts, NewShaper);
-+ {error, _} ->
-+ TargetSockMod:shutdown(TargetSocket, read_write)
-+ end.
-+
-+get_socket(PID) ->
-+ PID ! {get_socket, self()},
-+ receive
-+ {_SockMod, _Socket} = SockOpts ->
-+ SockOpts
-+ end.
-+
-+%% If any argument is a jid record, convert it to normalized string form...
-+activate(#jid{} = Initiator, Target, SessionID) ->
-+ NormalizedInitiator = jlib:jid_to_string(jlib:make_jid(jlib:jid_tolower(Initiator))),
-+ activate(NormalizedInitiator, Target, SessionID);
-+activate(Initiator, #jid{} = Target, SessionID) ->
-+ NormalizedTarget = jlib:jid_to_string(jlib:make_jid(jlib:jid_tolower(Target))),
-+ activate(Initiator, NormalizedTarget, SessionID);
-+%% ...and get on with the activation.
-+activate(Initiator, Target, SessionID) ->
-+ Cookie = sha:sha(SessionID ++ Initiator ++ Target),
-+ F = fun() ->
-+ case mnesia:read({proxy65_connection, Cookie}) of
-+ [#proxy65_connection{firstpid = FirstPID,
-+ secondpid = SecondPID}]
-+ when is_pid(FirstPID), is_pid(SecondPID) ->
-+ mnesia:delete({proxy65_connection, Cookie}),
-+ {FirstPID, SecondPID};
-+ _ ->
-+ error
-+ end
-+ end,
-+ case mnesia:transaction(F) of
-+ {atomic, {FirstPID, SecondPID}} ->
-+ FirstSocket = get_socket(FirstPID),
-+ SecondSocket = get_socket(SecondPID),
-+ FirstPID ! {activate, SecondSocket, Initiator, Target},
-+ SecondPID ! {activate, FirstSocket, Initiator, Target},
-+ ok;
-+ Error ->
-+ ?ERROR_MSG("Proxy activation failed: ~p", [Error]),
-+ error
-+ end.
diff --git a/net-im/ejabberd/files/ejabberd-1.1.2-statsdx-web.patch b/net-im/ejabberd/files/ejabberd-1.1.2-statsdx-web.patch
deleted file mode 100644
index 2182fb04..00000000
--- a/net-im/ejabberd/files/ejabberd-1.1.2-statsdx-web.patch
+++ /dev/null
@@ -1,318 +0,0 @@
---- ejabberd-1.1.1/src/web/ejabberd_web_admin.erl 2006-04-03 16:14:35.000000000 +0200
-+++ ejabberd-1.1.1-r1/src/web/ejabberd_web_admin.erl 2006-06-23 09:32:54.000000000 +0200
-@@ -905,7 +905,10 @@
- path = ["stats"],
- q = Query,
- lang = Lang} = Request) ->
-- Res = get_stats(Host, Lang),
-+ Res = case whereis(ejabberd_mod_statsdx) of
-+ undefined -> get_stats(Host, Lang);
-+ _ -> get_statsdx(Host, Lang)
-+ end,
- make_xhtml([?XCT("h1", "Statistics")] ++ Res, Host, Lang);
-
- process_admin(Host,
-@@ -1397,6 +1400,165 @@
- ])].
-
-
-+get_statsdx(global, Lang) ->
-+ [
-+ ?XC("h3", "Accounts"),
-+ ?XAE("table", [],
-+ [?XE("tbody", [
-+ do_stat(global, Lang, "registeredusers")
-+ ])
-+ ]),
-+ ?XC("h3", "Roster"),
-+ ?XAE("table", [],
-+ [?XE("tbody", [
-+ do_stat(global, Lang, "totalrosteritems"),
-+ do_stat(global, Lang, "meanitemsinroster")
-+ ])
-+ ]),
-+ ?XC("h3", "Users"),
-+ ?XAE("table", [],
-+ [?XE("tbody", [
-+ do_stat(global, Lang, "authusers"),
-+ do_stat(global, Lang, "onlineusers"),
-+ do_stat(global, Lang, "offlinemsg"),
-+ do_stat(global, Lang, "vcards")
-+ ])
-+ ]),
-+ ?XC("h3", "MUC"),
-+ ?XAE("table", [],
-+ [?XE("tbody", [
-+ do_stat(global, Lang, "totalmucrooms"),
-+ do_stat(global, Lang, "permmucrooms"),
-+ do_stat(global, Lang, "regmucrooms")
-+ ])
-+ ]),
-+ ?XC("h3", "Pub/Sub"),
-+ ?XAE("table", [],
-+ [?XE("tbody", [
-+ do_stat(global, Lang, "regpubsubnodes")
-+ ])
-+ ]),
-+ ?XC("h3", "IRC"),
-+ ?XAE("table", [],
-+ [?XE("tbody", [
-+ do_stat(global, Lang, "ircconns")
-+ ])
-+ ]),
-+ ?XC("h3", "Ratios"),
-+ ?XAE("table", [],
-+ [?XE("tbody", [
-+ ])
-+ ]),
-+ ?XC("h3", "Sessions: " ++ get_stat_n("client")),
-+ ?XAE("table", [],
-+ [?XE("tbody",
-+ do_stat_table(global, Lang, "client", server)
-+ )
-+ ]),
-+ ?XC("h3", "Sessions: " ++ get_stat_n("os")),
-+ ?XAE("table", [],
-+ [?XE("tbody",
-+ do_stat_table(global, Lang, "os", server)
-+ )
-+ ]),
-+ ?XC("h3", "Sessions: " ++ get_stat_n("client") ++ "/" ++ get_stat_n("os")),
-+ ?XAE("table", [],
-+ [?XE("tbody",
-+ do_stat_table(global, Lang, "client_os", server)
-+ )
-+ ]),
-+ ?XC("h3", "Sessions: " ++ get_stat_n("languages")),
-+ ?XAE("table", [],
-+ [?XE("tbody",
-+ do_stat_table(global, Lang, "languages", server)
-+ )
-+ ])
-+ ];
-+
-+get_statsdx(Host, Lang) ->
-+ [
-+ ?XC("h2", Host),
-+ ?XC("h3", "Accounts"),
-+ ?XAE("table", [],
-+ [?XE("tbody", [
-+ do_stat(global, Lang, "registeredusers", Host)
-+ ])
-+ ]),
-+ ?XC("h3", "Roster"),
-+ ?XAE("table", [],
-+ [?XE("tbody", [
-+ do_stat(global, Lang, "totalrosteritems", Host),
-+ do_stat(global, Lang, "meanitemsinroster", Host)
-+ ])
-+ ]),
-+ ?XC("h3", "Users"),
-+ ?XAE("table", [],
-+ [?XE("tbody", [
-+ do_stat(global, Lang, "authusers", Host),
-+ do_stat(global, Lang, "onlineusers", Host),
-+ do_stat(global, Lang, "offlinemsg", Host),
-+ do_stat(global, Lang, "vcards", Host)
-+ ])
-+ ]),
-+ ?XC("h3", "Connections"),
-+ ?XAE("table", [],
-+ [?XE("tbody", [
-+ do_stat(global, Lang, "s2sconnections", Host)
-+ ])
-+ ]),
-+ ?XC("h3", "MUC"),
-+ ?XAE("table", [],
-+ [?XE("tbody", [
-+ do_stat(global, Lang, "totalmucrooms", Host),
-+ do_stat(global, Lang, "permmucrooms", Host),
-+ do_stat(global, Lang, "regmucrooms", Host)
-+ ])
-+ ]),
-+ ?XC("h3", "IRC"),
-+ ?XAE("table", [],
-+ [?XE("tbody", [
-+ do_stat(global, Lang, "ircconns", Host)
-+ ])
-+ ]),
-+ %?XC("h3", "Pub/Sub"),
-+ %?XAE("table", [],
-+ % [?XE("tbody", [
-+ % do_stat(global, Lang, "regpubsubnodes", Host)
-+ % ])
-+ %]),
-+ ?XC("h3", "Ratios"),
-+ ?XAE("table", [],
-+ [?XE("tbody", [
-+ ])
-+ ]),
-+ ?XC("h3", "Sessions: " ++ get_stat_n("client")),
-+ ?XAE("table", [],
-+ [?XE("tbody",
-+ do_stat_table(global, Lang, "client", Host)
-+ )
-+ ]),
-+ ?XC("h3", "Sessions: " ++ get_stat_n("os")),
-+ ?XAE("table", [],
-+ [?XE("tbody",
-+ do_stat_table(global, Lang, "os", Host)
-+ )
-+ ]),
-+ ?XC("h3", "Sessions: " ++ get_stat_n("client") ++ "/" ++ get_stat_n("os")),
-+ ?XAE("table", [],
-+ [?XE("tbody",
-+ do_stat_table(global, Lang, "client_os", Host)
-+ )
-+ ]),
-+ ?XC("h3", "Sessions: " ++ get_stat_n("languages")),
-+ ?XAE("table", [],
-+ [?XE("tbody",
-+ do_stat_table(global, Lang, "languages", Host)
-+ )
-+ ])
-+ ].
-+
-+
-+
- list_online_users(Host, _Lang) ->
- Users = [{S, U} || {U, S, R} <- ejabberd_sm:get_vh_session_list(Host)],
- SUsers = lists:usort(Users),
-@@ -2015,6 +2177,12 @@
- ];
-
- get_node(global, Node, ["stats"], Query, Lang) ->
-+ Res = case whereis(ejabberd_mod_statsdx) of
-+ undefined -> get_node(global, Node, ["statslight"], Query, Lang);
-+ _ -> get_node(global, Node, ["statsdx"], Query, Lang)
-+ end;
-+
-+get_node(global, Node, ["statslight"], Query, Lang) ->
- UpTime = rpc:call(Node, erlang, statistics, [wall_clock]),
- UpTimeS = io_lib:format("~.3f", [element(1, UpTime)/1000]),
- CPUTime = rpc:call(Node, erlang, statistics, [runtime]),
-@@ -2089,9 +2257,124 @@
- ?XCT("h3", "Script check"), ?C(atom_to_list(Check))])
- ];
-
-+get_node(global, Node, ["statsdx"], Query, Lang) ->
-+ TransactionsCommited =
-+ rpc:call(Node, mnesia, system_info, [transaction_commits]),
-+ TransactionsAborted =
-+ rpc:call(Node, mnesia, system_info, [transaction_failures]),
-+ TransactionsRestarted =
-+ rpc:call(Node, mnesia, system_info, [transaction_restarts]),
-+ TransactionsLogged =
-+ rpc:call(Node, mnesia, system_info, [transaction_log_writes]),
-+
-+ [?XC("h1", io_lib:format(?T("~p statistics"), [Node])),
-+ ?XC("h3", "Connections"),
-+ ?XAE("table", [],
-+ [?XE("tbody", [
-+ do_stat(global, Lang, "authusers"),
-+ do_stat(Node, Lang, "httppollusers"),
-+ do_stat(Node, Lang, "s2sconnections"),
-+ do_stat(Node, Lang, "s2sservers")
-+ ])
-+ ]),
-+ ?XC("h3", "Erlang"),
-+ ?XAE("table", [],
-+ [?XE("tbody", [
-+ do_stat(Node, Lang, "operatingsystem"),
-+ do_stat(Node, Lang, "erlangmachine"),
-+ do_stat(Node, Lang, "erlangmachinetarget"),
-+ do_stat(Node, Lang, "maxprocallowed"),
-+ do_stat(Node, Lang, "procqueue"),
-+ do_stat(Node, Lang, "totalerlproc")
-+ ])
-+ ]),
-+ ?XC("h3", "Times"),
-+ ?XAE("table", [],
-+ [?XE("tbody", [
-+ do_stat(Node, Lang, "uptime"),
-+ do_stat(Node, Lang, "uptimehuman"),
-+ do_stat(Node, Lang, "lastrestart"),
-+ do_stat(Node, Lang, "cputime")
-+ ])
-+ ]),
-+ ?XC("h3", "CPU"),
-+ ?XAE("table", [],
-+ [?XE("tbody", [
-+ do_stat(Node, Lang, "cpu_avg1"),
-+ do_stat(Node, Lang, "cpu_avg5"),
-+ do_stat(Node, Lang, "cpu_avg15"),
-+ do_stat(Node, Lang, "cpu_nprocs")%,
-+ %do_stat(Node, Lang, "cpu_util_user"),
-+ %do_stat(Node, Lang, "cpu_nice_user"),
-+ %do_stat(Node, Lang, "cpu_kernel"),
-+ %do_stat(Node, Lang, "cpu_idle"),
-+ %do_stat(Node, Lang, "cpu_wait")
-+ ])
-+ ]),
-+ %?XC("h3", "RAM"),
-+ %?XAE("table", [],
-+ % [?XE("tbody", [
-+ %do_stat(Node, Lang, "memsup_system"),
-+ %do_stat(Node, Lang, "memsup_free"),
-+ %do_stat(Node, Lang, "reductions")
-+ % ])
-+ % ]),
-+ ?XC("h3", "Database"),
-+ ?XAE("table", [],
-+ [?XE("tbody", [
-+ ?XE("tr", [?XCT("td", "Transactions commited"),
-+ ?XAC("td", [{"class", "alignright"}],
-+ integer_to_list(TransactionsCommited))]),
-+ ?XE("tr", [?XCT("td", "Transactions aborted"),
-+ ?XAC("td", [{"class", "alignright"}],
-+ integer_to_list(TransactionsAborted))]),
-+ ?XE("tr", [?XCT("td", "Transactions restarted"),
-+ ?XAC("td", [{"class", "alignright"}],
-+ integer_to_list(TransactionsRestarted))]),
-+ ?XE("tr", [?XCT("td", "Transactions logged"),
-+ ?XAC("td", [{"class", "alignright"}],
-+ integer_to_list(TransactionsLogged))])
-+ ])
-+ ])];
-+
- get_node(Host, Node, NPath, Query, Lang) ->
- [?XCT("h1", "Not Found")].
-
-+do_table_element(Lang, L, N) ->
-+ ?XE("tr", [
-+ ?XCT("td", L),
-+ ?XAC("td", [{"class", "alignright"}],
-+ N)
-+ ]).
-+
-+do_stat_table(global, Lang, Stat, Host) ->
-+ Os = mod_statsdx:get(global, [Stat, Host]),
-+ lists:map(
-+ fun({L, N}) ->
-+ do_table_element(Lang, L, io_lib:format("~p", [N]))
-+ end,
-+ Os
-+ ).
-+
-+do_stat(Node, Lang, Stat) ->
-+ ?XE("tr", [
-+ ?XCT("td", get_stat_n(Stat)),
-+ ?XAC("td", [{"class", "alignright"}],
-+ get_stat_v(Node, [Stat]))]).
-+
-+do_stat(Node, Lang, Stat, Host) ->
-+ %[Res] = get_stat_v(Node, [Stat, Host]),
-+ %do_table_element(Lang, get_stat_n(Stat), Res).
-+ do_table_element(Lang, get_stat_n(Stat), get_stat_v(Node, [Stat, Host])).
-+
-+% Get a stat name
-+get_stat_n(Stat) ->
-+ mod_statsdx:get(foo, [Stat, title]).
-+% Get a stat value
-+get_stat_v(Node, Stat) -> get_stat_v2(mod_statsdx:get(Node, Stat)).
-+get_stat_v2(Value) when is_list(Value) -> Value;
-+get_stat_v2(Value) when is_float(Value) -> io_lib:format("~.4f", [Value]);
-+get_stat_v2(Value) -> io_lib:format("~p", [Value]).
-
- node_parse_query(Node, Query) ->
- case lists:keysearch("restart", 1, Query) of
diff --git a/net-im/ejabberd/files/ejabberd-1.1.2-statsdx.patch b/net-im/ejabberd/files/ejabberd-1.1.2-statsdx.patch
deleted file mode 100644
index 38383542..00000000
--- a/net-im/ejabberd/files/ejabberd-1.1.2-statsdx.patch
+++ /dev/null
@@ -1,742 +0,0 @@
-diff -Naur ejabberd-1.1.1/src/mod_statsdx.erl ejabberd-1.1.1-r1/src/mod_statsdx.erl
---- ejabberd-1.1.1/src/mod_statsdx.erl 1970-01-01 01:00:00.000000000 +0100
-+++ ejabberd-1.1.1-r1/src/mod_statsdx.erl 2006-05-12 23:14:17.000000000 +0200
-@@ -0,0 +1,738 @@
-+%%%----------------------------------------------------------------------
-+%%% File : mod_statsdx.erl
-+%%% Author : Badlop <badlop@ono.com>
-+%%% Purpose : Calculates and gathers statistics actively
-+%%% Created :
-+%%% Id : 0.2.3
-+%%%----------------------------------------------------------------------
-+
-+%%% INSTALL:
-+%%% 1 Copy this file to ejabberd/src/mod_statsdx.erl
-+%%% 2 Recompile ejabberd
-+%%% 3 Add to ejabberd.cfg, 'modules' section the basic configuration:
-+%%% {mod_statsdx, []},
-+
-+%%% CONFIGURE:
-+%%% hooks: Set to 'false' to remove hooks and related statistics if you don't need them (default: true)
-+
-+%%% EXAMPLE CONFIGURATION:
-+%%% {mod_statsdx, [{hooks, false}]},
-+
-+%%% FEATURE REQUESTS:
-+%%% - fix the problem with plain/ssl/tlsusers, it crashes ejabberd
-+%%% - traffic: send bytes per second, received bps
-+%%% - connections to a transport
-+%%% - traffic: send presence per second, received mps
-+%%% - Number of SASL c2s connections
-+%%% - improve to work in distributed server
-+
-+-module(mod_statsdx).
-+-author('').
-+-vsn('').
-+
-+-behaviour(gen_mod).
-+
-+-export([start/2, loop/0, stop/1, get/2,
-+ remove_user/2, user_send_packet/3, user_receive_packet/4,
-+ user_login/1, user_logout/4]).
-+
-+-include("ejabberd.hrl").
-+-include("jlib.hrl").
-+-include("mod_roster.hrl").
-+
-+-define(PROCNAME, ejabberd_mod_statsdx).
-+-define(T(Text), translate:translate("Lang", Text)).
-+
-+%% -------------------
-+%% Module control
-+%% -------------------
-+
-+start(Host, Opts) ->
-+ Hooks = gen_mod:get_opt(hooks, Opts, true),
-+ % Default value for the counters
-+ CD = case Hooks of
-+ true -> 0;
-+ false -> "disabled"
-+ end,
-+ case whereis(?PROCNAME) of
-+ undefined ->
-+ application:start(os_mon),
-+ ets:new(stats, [named_table, public]),
-+ ets:insert(stats, {{user_login, server}, CD}),
-+ ets:insert(stats, {{user_logout, server}, CD}),
-+ ets:insert(stats, {{remove_user, server}, CD}),
-+ lists:foreach(
-+ fun(E) -> ets:insert(stats, {{client, server, E}, CD}) end,
-+ list_elem(clients, id)
-+ ),
-+ lists:foreach(
-+ fun(E) -> ets:insert(stats, {{os, server, E}, CD}) end,
-+ list_elem(oss, id)
-+ ),
-+ register(?PROCNAME, spawn(?MODULE, loop, []));
-+ _ ->
-+ ok
-+ end,
-+ ets:insert(stats, {{user_login, Host}, CD}),
-+ ets:insert(stats, {{user_logout, Host}, CD}),
-+ ets:insert(stats, {{remove_user, Host}, CD}),
-+ ets:insert(stats, {{send, Host, iq, in}, CD}),
-+ ets:insert(stats, {{send, Host, iq, out}, CD}),
-+ ets:insert(stats, {{send, Host, message, in}, CD}),
-+ ets:insert(stats, {{send, Host, message, out}, CD}),
-+ ets:insert(stats, {{send, Host, presence, in}, CD}),
-+ ets:insert(stats, {{send, Host, presence, out}, CD}),
-+ ets:insert(stats, {{recv, Host, iq, in}, CD}),
-+ ets:insert(stats, {{recv, Host, iq, out}, CD}),
-+ ets:insert(stats, {{recv, Host, message, in}, CD}),
-+ ets:insert(stats, {{recv, Host, message, out}, CD}),
-+ ets:insert(stats, {{recv, Host, presence, in}, CD}),
-+ ets:insert(stats, {{recv, Host, presence, out}, CD}),
-+ lists:foreach(
-+ fun(E) -> ets:insert(stats, {{client, Host, E}, CD}) end,
-+ list_elem(clients, id)
-+ ),
-+ lists:foreach(
-+ fun(E) -> ets:insert(stats, {{os, Host, E}, CD}) end,
-+ list_elem(oss, id)
-+ ),
-+ case Hooks of
-+ true ->
-+ ejabberd_hooks:add(user_send_packet, Host, ?MODULE, user_send_packet, 90),
-+ ejabberd_hooks:add(user_receive_packet, Host, ?MODULE, user_receive_packet, 90),
-+ ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 90),
-+ ejabberd_hooks:add(user_available_hook, Host, ?MODULE, user_login, 90),
-+ ejabberd_hooks:add(unset_presence_hook, Host, ?MODULE, user_logout, 90);
-+ false ->
-+ ok
-+ end.
-+
-+loop() ->
-+ receive
-+ stop -> ok
-+ end.
-+
-+stop(Host) ->
-+ ejabberd_hooks:delete(user_send_packet, Host, ?MODULE, user_send_packet, 60),
-+ ejabberd_hooks:delete(user_receive_packet, Host, ?MODULE, user_receive_packet, 60),
-+ ejabberd_hooks:delete(remove_user, Host, ?MODULE, remove_user, 60),
-+ ets:delete(stats),
-+ case whereis(?PROCNAME) of
-+ undefined -> ok;
-+ _ ->
-+ ?PROCNAME ! stop
-+ end.
-+
-+
-+remove_user(_User, Server) ->
-+ ets:update_counter(stats, {remove_user, Server}, 1),
-+ ets:update_counter(stats, {remove_user, server}, 1).
-+
-+user_send_packet(FromJID, ToJID, NewEl) ->
-+ Host = FromJID#jid.lserver,
-+ HostTo = ToJID#jid.lserver,
-+ {xmlelement, Type, _, _} = NewEl,
-+ Type2 = case Type of
-+ "iq" -> iq;
-+ "message" -> message;
-+ "presence" -> presence
-+ end,
-+ Dest = case is_host(HostTo, Host) of
-+ true -> in;
-+ false -> out
-+ end,
-+ ets:update_counter(stats, {send, Host, Type2, Dest}, 1),
-+
-+ % Registrarse para tramitar Host/mod_stats2file
-+ case list_to_atom(ToJID#jid.lresource) of
-+ ?MODULE -> received_response(FromJID, ToJID, NewEl);
-+ _ -> ok
-+ end.
-+
-+user_receive_packet(_JID, From, To, FixedPacket) ->
-+ HostFrom = From#jid.lserver,
-+ Host = To#jid.lserver,
-+ {xmlelement, Type, _, _} = FixedPacket,
-+ Type2 = case Type of
-+ "iq" -> iq;
-+ "message" -> message;
-+ "presence" -> presence
-+ end,
-+ Dest = case is_host(HostFrom, Host) of
-+ true -> in;
-+ false -> out
-+ end,
-+ ets:update_counter(stats, {recv, Host, Type2, Dest}, 1).
-+
-+
-+%% -------------------
-+%% get(*
-+%% -------------------
-+
-+%gett(Arg) -> get(node(), [Arg, title]).
-+getl(Args) -> get(node(), [Args]).
-+getl(Args, Host) -> get(node(), [Args, Host]).
-+
-+%get(_Node, ["", title]) -> "";
-+
-+get(global, A) -> get(node(), A);
-+
-+get(_, [{"reductions", _}, title]) -> "Reductions (per minute)";
-+get(_, [{"reductions", I}]) -> calc_avg(element(2, statistics(reductions)), I); %+++
-+
-+get(_, ["cpu_avg1", title]) -> "Average system load (1 min)";
-+get(N, ["cpu_avg1"]) -> rpc:call(N, cpu_sup, avg1, [])/256;
-+get(_, ["cpu_avg5", title]) -> "Average system load (5 min)";
-+get(N, ["cpu_avg5"]) -> rpc:call(N, cpu_sup, avg1, [])/256;
-+get(_, ["cpu_avg15", title]) -> "Average system load (15 min)";
-+get(N, ["cpu_avg15"]) -> rpc:call(N, cpu_sup, avg15, [])/256;
-+get(_, ["cpu_nprocs", title]) -> "Number of UNIX processes running on this machine";
-+get(N, ["cpu_nprocs"]) -> rpc:call(N, cpu_sup, nprocs, []);
-+get(_, ["cpu_util", title]) -> "CPU utilization";
-+get(N, ["cpu_util"]) -> rpc:call(N, cpu_sup, util, []);
-+
-+get(_, [{"cpu_util_user", _}, title]) -> "CPU utilization - user";
-+get(_, [{"cpu_util_nice_user", _}, title]) -> "CPU utilization - nice_user";
-+get(_, [{"cpu_util_kernel", _}, title]) -> "CPU utilization - kernel";
-+get(_, [{"cpu_util_wait", _}, title]) -> "CPU utilization - wait";
-+get(_, [{"cpu_util_idle", _}, title]) -> "CPU utilization - idle";
-+get(_, [{"cpu_util_user", U}]) -> [{user, Us}, _, _] = element(2, U), Us;
-+get(_, [{"cpu_util_nice_user", U}]) -> [_, {nice_user, NU}, _] = element(2, U), NU;
-+get(_, [{"cpu_util_kernel", U}]) -> [_, _, {kernel, K}] = element(2, U), K;
-+get(_, [{"cpu_util_wait", U}]) ->
-+ case element(3, U) of
-+ [{wait, W}, {idle, _}] -> W; % Solaris
-+ [{idle, _}] -> 0
-+ end;
-+get(_, [{"cpu_util_idle", U}]) ->
-+ case element(3, U) of
-+ [{wait, _}, {idle, I}] -> I; % Solaris
-+ [{idle, I}] -> I
-+ end;
-+
-+get(_, [{"client", Id}, title]) -> atom_to_list(Id);
-+get(_, [{"client", Id}, Host]) -> [{_, C}] = ets:lookup(stats, {client, Host, Id}), C;
-+get(_, ["client", title]) -> "Client";
-+get(N, ["client", Host]) ->
-+ lists:map(
-+ fun(Id) ->
-+ [Id_string] = io_lib:format("~p", [Id]),
-+ {Id_string, get(N, [{"client", Id}, Host])}
-+ end,
-+ lists:usort(list_elem(clients, id))
-+ );
-+
-+get(_, [{"os", Id}, title]) -> atom_to_list(Id);
-+get(_, [{"os", Id}, list]) -> lists:usort(list_elem(oss, Id));
-+get(_, [{"os", Id}, Host]) -> [{_, C}] = ets:lookup(stats, {os, Host, Id}), C;
-+get(_, ["os", title]) -> "Operating System";
-+get(N, ["os", Host]) ->
-+ lists:map(
-+ fun(Id) ->
-+ [Id_string] = io_lib:format("~p", [Id]),
-+ {Id_string, get(N, [{"os", Id}, Host])}
-+ end,
-+ lists:usort(list_elem(oss, id))
-+ );
-+
-+get(_, [{"memsup_system", _}, title]) -> "Memory physical (bytes)";
-+get(_, [{"memsup_system", M}]) -> [_, _, {system_total_memory, R}] = M, R;
-+get(_, [{"memsup_free", _}, title]) -> "Memory free (bytes)";
-+get(_, [{"memsup_free", M}]) -> [_, {free_memory, R}, _] = M, R;
-+
-+get(_, [{"user_login", _}, title]) -> "Logins (per minute)";
-+get(_, [{"user_login", I}, Host]) -> get_stat({user_login, Host}, I);
-+get(_, [{"user_logout", _}, title]) -> "Logouts (per minute)";
-+get(_, [{"user_logout", I}, Host]) -> get_stat({user_logout, Host}, I);
-+get(_, [{"remove_user", _}, title]) -> "Accounts deleted (per minute)";
-+get(_, [{"remove_user", I}, Host]) -> get_stat({remove_user, Host}, I);
-+get(_, [{Table, Type, Dest, _}, title]) -> filename:flatten([Table, Type, Dest]);
-+get(_, [{Table, Type, Dest, I}, Host]) -> get_stat({Table, Host, Type, Dest}, I);
-+
-+get(_, ["localtime", title]) -> "Local time";
-+get(N, ["localtime"]) ->
-+ localtime_to_string(rpc:call(N, erlang, localtime, []));
-+
-+get(_, ["vhost", title]) -> "Virtual host";
-+get(_, ["vhost", Host]) -> Host;
-+
-+get(_, ["totalerlproc", title]) -> "Total Erlang processes running";
-+get(N, ["totalerlproc"]) -> rpc:call(N, erlang, system_info, [process_count]);
-+get(_, ["operatingsystem", title]) -> "Operating System";
-+get(N, ["operatingsystem"]) -> {rpc:call(N, os, type, []), rpc:call(N, os, version, [])};
-+get(_, ["erlangmachine", title]) -> "Erlang machine";
-+get(N, ["erlangmachine"]) -> rpc:call(N, erlang, system_info, [system_version]);
-+get(_, ["erlangmachinetarget", title]) -> "Erlang machine target";
-+get(N, ["erlangmachinetarget"]) -> rpc:call(N, erlang, system_info, [system_architecture]);
-+get(_, ["maxprocallowed", title]) -> "Maximum processes allowed";
-+get(N, ["maxprocallowed"]) -> rpc:call(N, erlang, system_info, [process_limit]);
-+get(_, ["procqueue", title]) -> "Number of processes on the running queue";
-+get(N, ["procqueue"]) -> rpc:call(N, erlang, statistics, [run_queue]);
-+get(_, ["uptimehuman", title]) -> "Uptime";
-+get(N, ["uptimehuman"]) ->
-+ io_lib:format("~w days ~w hours ~w minutes ~p seconds", ms_to_time(get(N, ["uptime"])));
-+get(_, ["lastrestart", title]) -> "Last restart";
-+get(N, ["lastrestart"]) ->
-+ Now = calendar:datetime_to_gregorian_seconds(rpc:call(N, erlang, localtime, [])),
-+ UptimeMS = get(N, ["uptime"]),
-+ Last_restartS = trunc(Now - (UptimeMS/1000)),
-+ Last_restart = calendar:gregorian_seconds_to_datetime(Last_restartS),
-+ localtime_to_string(Last_restart);
-+
-+get(_, ["plainusers", title]) -> "Plain users";
-+get(_, ["plainusers"]) -> {R, _, _} = get_connectiontype(), R;
-+get(_, ["tlsusers", title]) -> "TLS users";
-+get(_, ["tlsusers"]) -> {_, R, _} = get_connectiontype(), R;
-+get(_, ["sslusers", title]) -> "SSL users";
-+get(_, ["sslusers"]) -> {_, _, R} = get_connectiontype(), R;
-+get(_, ["registeredusers", title]) -> "Registered users";
-+get(N, ["registeredusers"]) -> rpc:call(N, mnesia, table_info, [passwd, size]);
-+get(_, ["registeredusers", Host]) -> length(ejabberd_auth:get_vh_registered_users(Host));
-+get(_, ["authusers", title]) -> "Authenticated users";
-+get(N, ["authusers"]) -> rpc:call(N, mnesia, table_info, [session, size]);
-+get(_, ["authusers", Host]) -> get_authusers(Host);
-+get(_, ["onlineusers", title]) -> "Online users";
-+get(N, ["onlineusers"]) -> rpc:call(N, mnesia, table_info, [presence, size]);
-+get(_, ["onlineusers", Host]) -> length(ejabberd_sm:get_vh_session_list(Host));
-+get(_, ["httppollusers", title]) -> "HTTP-Poll users (aprox)";
-+get(N, ["httppollusers"]) -> rpc:call(N, mnesia, table_info, [http_poll, size]);
-+
-+get(_, ["s2sconnections", title]) -> "Outgoing S2S connections";
-+get(_, ["s2sconnections"]) -> length(get_S2SConns());
-+get(_, ["s2sconnections", Host]) -> get_s2sconnections(Host);
-+get(_, ["s2sservers", title]) -> "Outgoing S2S servers";
-+get(_, ["s2sservers"]) -> length(lists:usort([element(2, C) || C <- get_S2SConns()]));
-+
-+get(_, ["offlinemsg", title]) -> "Offline messages";
-+get(N, ["offlinemsg"]) -> rpc:call(N, mnesia, table_info, [offline_msg, size]);
-+get(_, ["offlinemsg", Host]) -> get_offlinemsg(Host);
-+get(_, ["totalrosteritems", title]) -> "Total roster items";
-+get(N, ["totalrosteritems"]) -> rpc:call(N, mnesia, table_info, [roster, size]);
-+get(_, ["totalrosteritems", Host]) -> get_totalrosteritems(Host);
-+
-+get(_, ["meanitemsinroster", title]) -> "Mean items in roster";
-+get(_, ["meanitemsinroster"]) -> get_meanitemsinroster();
-+get(_, ["meanitemsinroster", Host]) -> get_meanitemsinroster(Host);
-+
-+get(_, ["totalmucrooms", title]) -> "Total MUC rooms";
-+get(_, ["totalmucrooms"]) -> ets:info(muc_online_room, size);
-+get(_, ["totalmucrooms", Host]) -> get_totalmucrooms(Host);
-+get(_, ["permmucrooms", title]) -> "Permanent MUC rooms";
-+get(N, ["permmucrooms"]) -> rpc:call(N, mnesia, table_info, [muc_room, size]);
-+get(_, ["permmucrooms", Host]) -> get_permmucrooms(Host);
-+get(_, ["regmucrooms", title]) -> "Users registered at MUC service";
-+get(N, ["regmucrooms"]) -> rpc:call(N, mnesia, table_info, [muc_registered, size]);
-+get(_, ["regmucrooms", Host]) -> get_regmucrooms(Host);
-+get(_, ["regpubsubnodes", title]) -> "Registered nodes at Pub/Sub";
-+get(N, ["regpubsubnodes"]) -> rpc:call(N, mnesia, table_info, [pubsub_node, size]);
-+get(_, ["vcards", title]) -> "Total vCards published";
-+get(N, ["vcards"]) -> rpc:call(N, mnesia, table_info, [vcard, size]);
-+get(_, ["vcards", Host]) -> get_vcards(Host);
-+
-+get(_, ["ircconns", title]) -> "IRC connections";
-+get(_, ["ircconns"]) -> ets:info(irc_connection, size);
-+get(_, ["ircconns", Host]) -> get_irccons(Host);
-+get(_, ["uptime", title]) -> "Uptime";
-+get(N, ["uptime"]) -> element(1, rpc:call(N, erlang, statistics, [wall_clock]));
-+get(_, ["cputime", title]) -> "CPU Time";
-+get(N, ["cputime"]) -> element(1, rpc:call(N, erlang, statistics, [runtime]));
-+
-+get(_, ["languages", title]) -> "Languages";
-+get(_, ["languages", Server]) -> get_languages(Server);
-+
-+get(_, ["client_os", title]) -> "Client/OS";
-+get(_, ["client_os", Server]) -> get_client_os(Server);
-+
-+get(N, A) ->
-+ io:format(" ----- node: '~p', A: '~p'~n", [N, A]),
-+ "666".
-+
-+%% -------------------
-+%% get_*
-+%% -------------------
-+
-+get_S2SConns() -> ejabberd_s2s:dirty_get_connections().
-+
-+get_tls_drv() ->
-+ R = lists:filter(
-+ fun(P) ->
-+ case erlang:port_info(P, name) of
-+ {name, "tls_drv"} -> true;
-+ _ -> false
-+ end
-+ end, erlang:ports()),
-+ length(R).
-+
-+get_connections(Port) ->
-+ R = lists:filter(
-+ fun(P) ->
-+ case inet:port(P) of
-+ {ok, Port} -> true;
-+ _ -> false
-+ end
-+ end, erlang:ports()),
-+ length(R).
-+
-+get_totalrosteritems(Host) ->
-+ F = fun() ->
-+ F2 = fun(R, {H, A}) ->
-+ {_LUser, LServer, _LJID} = R#roster.usj,
-+ A2 = case LServer of
-+ H -> A+1;
-+ _ -> A
-+ end,
-+ {H, A2}
-+ end,
-+ mnesia:foldl(F2, {Host, 0}, roster)
-+ end,
-+ {atomic, {Host, Res}} = mnesia:transaction(F),
-+ Res.
-+
-+% Copied from ejabberd_sm.erl
-+-record(session, {sid, usr, us, priority}).
-+
-+get_authusers(Host) ->
-+ F = fun() ->
-+ F2 = fun(R, {H, A}) ->
-+ {_LUser, LServer, _LResource} = R#session.usr,
-+ A2 = case LServer of
-+ H -> A+1;
-+ _ -> A
-+ end,
-+ {H, A2}
-+ end,
-+ mnesia:foldl(F2, {Host, 0}, session)
-+ end,
-+ {atomic, {Host, Res}} = mnesia:transaction(F),
-+ Res.
-+
-+-record(offline_msg, {us, timestamp, expire, from, to, packet}).
-+
-+get_offlinemsg(Host) ->
-+ F = fun() ->
-+ F2 = fun(R, {H, A}) ->
-+ {_LUser, LServer} = R#offline_msg.us,
-+ A2 = case LServer of
-+ H -> A+1;
-+ _ -> A
-+ end,
-+ {H, A2}
-+ end,
-+ mnesia:foldl(F2, {Host, 0}, offline_msg)
-+ end,
-+ {atomic, {Host, Res}} = mnesia:transaction(F),
-+ Res.
-+
-+-record(vcard, {us, vcard}).
-+
-+get_vcards(Host) ->
-+ F = fun() ->
-+ F2 = fun(R, {H, A}) ->
-+ {_LUser, LServer} = R#vcard.us,
-+ A2 = case LServer of
-+ H -> A+1;
-+ _ -> A
-+ end,
-+ {H, A2}
-+ end,
-+ mnesia:foldl(F2, {Host, 0}, vcard)
-+ end,
-+ {atomic, {Host, Res}} = mnesia:transaction(F),
-+ Res.
-+
-+-record(s2s, {fromto, pid, key}).
-+
-+get_s2sconnections(Host) ->
-+ F = fun() ->
-+ F2 = fun(R, {H, A}) ->
-+ {MyServer, _Server} = R#s2s.fromto,
-+ A2 = case MyServer of
-+ H -> A+1;
-+ _ -> A
-+ end,
-+ {H, A2}
-+ end,
-+ mnesia:foldl(F2, {Host, 0}, s2s)
-+ end,
-+ {atomic, {Host, Res}} = mnesia:transaction(F),
-+ Res.
-+
-+-record(irc_connection, {jid_server_host, pid}).
-+
-+get_irccons(Host) ->
-+ F2 = fun(R, {H, A}) ->
-+ {From, _Server, _Host} = R#irc_connection.jid_server_host,
-+ A2 = case From#jid.lserver of
-+ H -> A+1;
-+ _ -> A
-+ end,
-+ {H, A2}
-+ end,
-+ {Host, Res} = ets:foldl(F2, {Host, 0}, irc_connection),
-+ Res.
-+
-+is_host(Host, Subhost) ->
-+ Pos = string:len(Host)-string:len(Subhost)+1,
-+ case string:rstr(Host, Subhost) of
-+ Pos -> true;
-+ _ -> false
-+ end.
-+
-+-record(muc_online_room, {name_host, pid}).
-+
-+get_totalmucrooms(Host) ->
-+ F2 = fun(R, {H, A}) ->
-+ {_Name, MUCHost} = R#muc_online_room.name_host,
-+ A2 = case is_host(MUCHost, H) of
-+ true -> A+1;
-+ false -> A
-+ end,
-+ {H, A2}
-+ end,
-+ {Host, Res} = ets:foldl(F2, {Host, 0}, muc_online_room),
-+ Res.
-+
-+-record(muc_room, {name_host, opts}).
-+
-+get_permmucrooms(Host) ->
-+ F = fun() ->
-+ F2 = fun(R, {H, A}) ->
-+ {_Name, MUCHost} = R#muc_room.name_host,
-+ A2 = case is_host(MUCHost, H) of
-+ true -> A+1;
-+ false -> A
-+ end,
-+ {H, A2}
-+ end,
-+ mnesia:foldl(F2, {Host, 0}, muc_room)
-+ end,
-+ {atomic, {Host, Res}} = mnesia:transaction(F),
-+ Res.
-+
-+-record(muc_registered, {us_host, nick}).
-+
-+get_regmucrooms(Host) ->
-+ F = fun() ->
-+ F2 = fun(R, {H, A}) ->
-+ {_User, MUCHost} = R#muc_registered.us_host,
-+ A2 = case is_host(MUCHost, H) of
-+ true -> A+1;
-+ false -> A
-+ end,
-+ {H, A2}
-+ end,
-+ mnesia:foldl(F2, {Host, 0}, muc_registered)
-+ end,
-+ {atomic, {Host, Res}} = mnesia:transaction(F),
-+ Res.
-+
-+get_stat(Stat, Ims) ->
-+ Res = ets:lookup(stats, Stat),
-+ ets:update_counter(stats, Stat, {2,1,0,0}),
-+ [{_, C}] = Res,
-+ calc_avg(C, Ims).
-+ %C.
-+
-+calc_avg(Count, TimeMS) ->
-+ TimeMIN = TimeMS/(1000*60),
-+ Count/TimeMIN.
-+
-+%% -------------------
-+%% utilities
-+%% -------------------
-+
-+get_connectiontype() ->
-+ C2 = get_connections(5222) -1,
-+ C3 = get_connections(5223) -1,
-+ NUplain = C2 + C3 - get_tls_drv(),
-+ NUtls = C2 - NUplain,
-+ NUssl = C3,
-+ {NUplain, NUtls, NUssl}.
-+
-+ms_to_time(T) ->
-+ DMS = 24*60*60*1000,
-+ HMS = 60*60*1000,
-+ MMS = 60*1000,
-+ SMS = 1000,
-+ D = trunc(T/DMS),
-+ H = trunc((T - (D*DMS)) / HMS),
-+ M = trunc((T - (D*DMS) - (H*HMS)) / MMS),
-+ S = trunc((T - (D*DMS) - (H*HMS) - (M*MMS)) / SMS),
-+ [D, H, M, S].
-+
-+
-+% Cuando un usuario conecta, pedirle iq:version a nombre de Host/mod_stats2file
-+user_login(U) ->
-+ User = U#jid.luser,
-+ Host = U#jid.lserver,
-+ Resource = U#jid.lresource,
-+ ets:update_counter(stats, {user_login, server}, 1),
-+ ets:update_counter(stats, {user_login, Host}, 1),
-+ request_iqversion(User, Host, Resource).
-+
-+% cuando un usuario desconecta, buscar en la tabla su JID/USR y quitarlo
-+user_logout(User, Host, Resource, _Status) ->
-+ ets:update_counter(stats, {user_logout, server}, 1),
-+ ets:update_counter(stats, {user_logout, Host}, 1),
-+
-+ JID = jlib:make_jid(User, Host, Resource),
-+ case ets:lookup(stats, {session, JID}) of
-+ [{_, Client_id, OS_id, Lang}] ->
-+ ets:delete(stats, {session, JID}),
-+ ets:update_counter(stats, {client, Host, Client_id}, -1),
-+ ets:update_counter(stats, {client, server, Client_id}, -1),
-+ ets:update_counter(stats, {os, Host, OS_id}, -1),
-+ ets:update_counter(stats, {os, server, OS_id}, -1),
-+ update_counter_create(stats, {client_os, Host, Client_id, OS_id}, -1),
-+ update_counter_create(stats, {client_os, server, Client_id, OS_id}, -1),
-+ update_counter_create(stats, {lang, Host, Lang}, -1),
-+ update_counter_create(stats, {lang, server, Lang}, -1);
-+ [] ->
-+ ok
-+ end.
-+
-+request_iqversion(User, Host, Resource) ->
-+ From = jlib:make_jid("", Host, atom_to_list(?MODULE)),
-+ FromStr = jlib:jid_to_string(From),
-+ To = jlib:make_jid(User, Host, Resource),
-+ ToStr = jlib:jid_to_string(To),
-+ Packet = {xmlelement,"iq",
-+ [{"from",FromStr}, {"to",ToStr}, {"type","get"}, {"xml:lang","es"}],
-+ [{xmlcdata,"\n"}, {xmlcdata," "}, {xmlelement, "query", [{"xmlns","jabber:iq:version"}], []}, {xmlcdata,"\n"}]},
-+ ejabberd_local:route(From, To, Packet).
-+
-+% cuando el virtualJID recibe una respuesta iqversion,
-+% almacenar su JID/USR + client + OS en una tabla
-+received_response(From, _To, {xmlelement, "iq", Attrs, Elc}) ->
-+ User = From#jid.luser,
-+ Host = From#jid.lserver,
-+ Resource = From#jid.lresource,
-+
-+ "result" = xml:get_attr_s("type", Attrs),
-+ Lang = case xml:get_attr_s("xml:lang", Attrs) of
-+ [] -> "unknown";
-+ L -> L
-+ end,
-+ update_counter_create(stats, {lang, Host, Lang}, 1),
-+ update_counter_create(stats, {lang, server, Lang}, 1),
-+
-+ [El] = xml:remove_cdata(Elc),
-+ {xmlelement, _, Attrs2, _Els2} = El,
-+ ?NS_VERSION = xml:get_attr_s("xmlns", Attrs2),
-+
-+ Client = get_tag_cdata_subtag(El, "name"),
-+ %Version = get_tag_cdata_subtag(El, "version"),
-+ OS = get_tag_cdata_subtag(El, "os"),
-+ {Client_id, OS_id} = identify(Client, OS),
-+
-+ ets:update_counter(stats, {client, Host, Client_id}, 1),
-+ ets:update_counter(stats, {client, server, Client_id}, 1),
-+ ets:update_counter(stats, {os, Host, OS_id}, 1),
-+ ets:update_counter(stats, {os, server, OS_id}, 1),
-+ update_counter_create(stats, {client_os, Host, Client_id, OS_id}, 1),
-+ update_counter_create(stats, {client_os, server, Client_id, OS_id}, 1),
-+
-+ JID = jlib:make_jid(User, Host, Resource),
-+ ets:insert(stats, {{session, JID}, Client_id, OS_id, Lang}).
-+
-+update_counter_create(Table, Element, C) ->
-+ case ets:lookup(Table, Element) of
-+ [] -> ets:insert(Table, {Element, 1});
-+ _ -> ets:update_counter(Table, Element, C)
-+ end.
-+
-+get_tag_cdata_subtag(E, T) ->
-+ E2 = xml:get_subtag(E, T),
-+ case E2 of
-+ false -> "unknown";
-+ _ -> xml:get_tag_cdata(E2)
-+ end.
-+
-+list_elem(Type, id) ->
-+ {_, Ids} = lists:unzip(list_elem(Type, full)),
-+ Ids;
-+list_elem(clients, full) ->
-+ [
-+ {"gaim", gaim},
-+ {"Gajim", gajim},
-+ {"Tkabber", tkabber},
-+ {"Psi", psi},
-+ {"Pandion", pandion},
-+ {"Kopete", kopete},
-+ {"Exodus", exodus},
-+ {"libgaim", libgaim},
-+ {"JBother", jbother},
-+ {"iChat", ichat},
-+ {"Miranda", miranda},
-+ {"Trillian", trillian},
-+ {"JAJC", jajc},
-+ {"Coccinella", coccinella},
-+ {"Gabber", gabber},
-+ {"BitlBee", bitlbee},
-+ {"jabber.el", jabberel},
-+ {"unknown", unknown}
-+ ];
-+list_elem(oss, full) ->
-+ [
-+ {"Linux", linux},
-+ {"Win", windows},
-+ {"Gentoo", linux},
-+ {"Mac", mac},
-+ {"BSD", bsd},
-+ {"SunOS", linux},
-+ {"Ubuntu", linux},
-+ {"unknown", unknown}
-+ ].
-+
-+identify(Client, OS) ->
-+ Res = {try_match(Client, list_elem(clients, full)), try_match(OS, list_elem(oss, full))},
-+ case Res of
-+ {libgaim, mac} -> {adium, mac};
-+ _ -> Res
-+ end.
-+
-+try_match(_E, []) -> unknown;
-+try_match(E, [{Str, Id} | L]) ->
-+ case string:str(E, Str) of
-+ 0 -> try_match(E, L);
-+ _ -> Id
-+ end.
-+
-+get_client_os(Server) ->
-+ CO1 = ets:match(stats, {{client_os, Server, '$1', '$2'}, '$3'}),
-+ CO2 = lists:map(
-+ fun([Cl, Os, A3]) ->
-+ {lists:flatten([atom_to_list(Cl), "/", atom_to_list(Os)]), A3}
-+ end,
-+ CO1
-+ ),
-+ lists:keysort(1, CO2).
-+
-+get_languages(Server) ->
-+ L1 = ets:match(stats, {{lang, Server, '$1'}, '$2'}),
-+ L2 = lists:map(
-+ fun([La, C]) ->
-+ {La, C}
-+ end,
-+ L1
-+ ),
-+ lists:keysort(1, L2).
-+
-+get_meanitemsinroster() ->
-+ get_meanitemsinroster2(getl("totalrosteritems"), getl("registeredusers")).
-+get_meanitemsinroster(Host) ->
-+ get_meanitemsinroster2(getl("totalrosteritems", Host), getl("registeredusers", Host)).
-+get_meanitemsinroster2(Items, Users) ->
-+ case Users of
-+ 0 -> 0;
-+ _ -> Items/Users
-+ end.
-+
-+localtime_to_string({{Y, Mo, D},{H, Mi, S}}) ->
-+ lists:concat([H, ":", Mi, ":", S, " ", D, "/", Mo, "/", Y]).
-+
-+% cuando toque mostrar estadisticas
-+%get_iqversion() ->
-+ % contar en la tabla cuantos tienen cliente: *psi*
-+ %buscar en la tabla iqversion
-+ %ok.
diff --git a/net-im/ejabberd/files/ejabberd-1.1.2.initd b/net-im/ejabberd/files/ejabberd-1.1.2.initd
deleted file mode 100644
index 4291e39a..00000000
--- a/net-im/ejabberd/files/ejabberd-1.1.2.initd
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/sbin/runscript
-# Copyright 1999-2005 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-# $Header: /var/cvsroot/gentoo-x86/net-im/ejabberd/files/ejabberd-1.1.1.initd,v 1.1 2006/06/19 14:07:20 chainsaw Exp $
-
-opts="${opts} reload"
-
-depend() {
- use dns
- need net
- provide jabber-server
-}
-
-checkconfig() {
- if [ ! -e /etc/jabber/ejabberd.cfg ] ; then
- eerror "You need an /etc/jabber/ejabberd.cfg file to run ejabberd"
- return 1
- fi
-}
-
-start() {
- checkconfig || return 1
- ebegin "Starting eJabberd"
- su jabber -c "HOME=/var/run/jabber /usr/bin/ejabberd -noshell -detached"
- eend $?
-}
-
-stop() {
- ebegin "Stopping eJabberd"
- if [ -z "$EJABBERD_NODE" ];
- then
- EJABBERD_NODE="ejabberd@`hostname -s`"
- fi
- /usr/bin/ejabberdctl $EJABBERD_NODE stop
- eend $?
-}
-
-# Work around a bug in /sbin/runscript.sh - it won't run our custom
-# restart() unless it finds these two strings in the file.
-# svc_start svc_stop
-restart() {
- ebegin "Restarting eJabberd"
- if [ -z "$EJABBERD_NODE" ];
- then
- EJABBERD_NODE="ejabberd@`hostname -s`"
- fi
- /usr/bin/ejabberdctl $EJABBERD_NODE restart
- eend $?
-}
-
-reload() {
- ebegin "Reloading eJabberd"
- if [ -z "$EJABBERD_NODE" ];
- then
- EJABBERD_NODE="ejabberd@`hostname -s`"
- fi
- /usr/bin/ejabberdctl $EJABBERD_NODE reopen-log
- eend $?
-}
diff --git a/net-im/ejabberd/files/http_binding.patch b/net-im/ejabberd/files/http_binding.patch
deleted file mode 100644
index 95b2deae..00000000
--- a/net-im/ejabberd/files/http_binding.patch
+++ /dev/null
@@ -1,1006 +0,0 @@
-Index: src/ejabberd.cfg.example
-===================================================================
---- src/ejabberd.cfg.example (Revision 565)
-+++ src/ejabberd.cfg.example (Arbeitskopie)
-@@ -124,7 +124,7 @@
- {5269, ejabberd_s2s_in, [{shaper, s2s_shaper},
- {max_stanza_size, 131072}
- ]},
-- {5280, ejabberd_http, [http_poll, web_admin]},
-+ {5280, ejabberd_http, [http_poll, http_bind, web_admin]},
- {8888, ejabberd_service, [{access, all},
- {hosts, ["icq.localhost", "sms.localhost"],
- [{password, "secret"}]}]}
-Index: src/web/Makefile.in
-===================================================================
---- src/web/Makefile.in (Revision 565)
-+++ src/web/Makefile.in (Arbeitskopie)
-@@ -15,7 +15,8 @@
- $(OUTDIR)/ejabberd_http.beam \
- $(OUTDIR)/ejabberd_web.beam \
- $(OUTDIR)/ejabberd_web_admin.beam \
-- $(OUTDIR)/ejabberd_http_poll.beam
-+ $(OUTDIR)/ejabberd_http_poll.beam \
-+ $(OUTDIR)/ejabberd_http_bind.beam
-
- all: $(OBJS)
-
-Index: src/web/ejabberd_http_bind.erl
-===================================================================
---- src/web/ejabberd_http_bind.erl (Revision 0)
-+++ src/web/ejabberd_http_bind.erl (Revision 0)
-@@ -0,0 +1,804 @@
-+%%%----------------------------------------------------------------------
-+%%% File : ejabberd_http_bind.erl
-+%%% Author : Stefan Strigler <steve@zeank.in-berlin.de>
-+%%% Purpose : HTTP Binding support (JEP-0124)
-+%%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de>
-+%%% Id : $Id: $
-+%%%----------------------------------------------------------------------
-+
-+-module(ejabberd_http_bind).
-+-author('steve@zeank.in-berlin.de').
-+-vsn('Revision: 1.4').
-+
-+-behaviour(gen_fsm).
-+
-+%% External exports
-+-export([start_link/2,
-+ init/1,
-+ handle_event/3,
-+ handle_sync_event/4,
-+ code_change/4,
-+ handle_info/3,
-+ terminate/3,
-+ send/2,
-+ setopts/2,
-+ controlling_process/2,
-+ close/1,
-+ process_request/1]).
-+
-+%%-define(ejabberd_debug, true).
-+
-+-include("ejabberd.hrl").
-+-include("jlib.hrl").
-+-include("ejabberd_http.hrl").
-+
-+-record(http_bind, {id, pid, to, hold, wait}).
-+
-+%% http binding request
-+-record(hbr, {rid,
-+ key,
-+ in,
-+ out}).
-+
-+-record(state, {id,
-+ rid = error,
-+ key,
-+ output = "",
-+ input = "",
-+ waiting_input = false,
-+ last_receiver,
-+ last_poll,
-+ ctime = 0,
-+ timer,
-+ req_list = [] % list of requests
-+ }).
-+
-+
-+%-define(DBGFSM, true).
-+
-+-ifdef(DBGFSM).
-+-define(FSMOPTS, [{debug, [trace]}]).
-+-else.
-+-define(FSMOPTS, []).
-+-endif.
-+
-+-define(MAX_REQUESTS, 2). % number of simultaneous requests
-+-define(MIN_POLLING, "2"). % don't poll faster than that or we will shoot you
-+-define(MAX_WAIT, 60). % max num of secs to keep a request on hold
-+-define(MAX_INACTIVITY, 30000). % msecs to wait before terminating idle sessions
-+-define(CT, {"Content-Type", "text/xml; charset=utf-8"}).
-+-define(BAD_REQUEST, ?CT).
-+
-+
-+%%%----------------------------------------------------------------------
-+%%% API
-+%%%----------------------------------------------------------------------
-+start(ID, Key) ->
-+ mnesia:create_table(http_bind,
-+ [{ram_copies, [node()]},
-+ {attributes, record_info(fields, http_bind)}]),
-+ supervisor:start_child(ejabberd_http_bind_sup, [ID, Key]).
-+
-+start_link(ID, Key) ->
-+ gen_fsm:start_link(?MODULE, [ID, Key], ?FSMOPTS).
-+
-+send({http_bind, FsmRef}, Packet) ->
-+ gen_fsm:sync_send_all_state_event(FsmRef, {send, Packet}).
-+
-+setopts({http_bind, FsmRef}, Opts) ->
-+ case lists:member({active, once}, Opts) of
-+ true ->
-+ gen_fsm:sync_send_all_state_event(FsmRef, activate);
-+ _ ->
-+ ok
-+ end.
-+
-+controlling_process(_Socket, _Pid) ->
-+ ok.
-+
-+close({http_bind, FsmRef}) ->
-+ catch gen_fsm:sync_send_all_state_event(FsmRef, close).
-+
-+
-+process_request(#request{path = [],
-+ data = Data}) ->
-+ case catch parse_request(Data) of
-+ {ok, ID1, RID, Key, NewKey, Attrs, Packet} ->
-+ XmppDomain = xml:get_attr_s("to",Attrs),
-+ if
-+ (ID1 == "") and (XmppDomain == "") ->
-+ {200, [?CT], "<body type='terminate' "
-+ "condition='improper-addressing' "
-+ "xmlns='http://jabber.org/protocol/httpbind'/>"};
-+ true ->
-+ ID = if
-+ (ID1 == "") ->
-+ %% create new session
-+ NewID = sha:sha(term_to_binary({now(), make_ref()})),
-+ {ok, Pid} = start(NewID, Key),
-+ Wait = case
-+ string:to_integer(xml:get_attr_s("wait",Attrs))
-+ of
-+ {error, _} ->
-+ ?MAX_WAIT;
-+ {CWait, _} ->
-+ if
-+ (CWait > ?MAX_WAIT) ->
-+ ?MAX_WAIT;
-+ true ->
-+ CWait
-+ end
-+ end,
-+ Hold = case
-+ string:to_integer(
-+ xml:get_attr_s("hold",Attrs))
-+ of
-+ {error, _} ->
-+ (?MAX_REQUESTS - 1);
-+ {CHold, _} ->
-+ if
-+ (CHold > (?MAX_REQUESTS - 1)) ->
-+ (?MAX_REQUESTS - 1);
-+ true ->
-+ CHold
-+ end
-+ end,
-+ mnesia:transaction(
-+ fun() ->
-+ mnesia:write(#http_bind{id = NewID,
-+ pid = Pid,
-+ to = XmppDomain,
-+ wait = Wait,
-+ hold = Hold})
-+ end),
-+ StreamStart = if
-+ (XmppDomain /= "") ->
-+ true;
-+ true ->
-+ false
-+ end,
-+ InPacket = Packet,
-+ NewID;
-+ true ->
-+ %% old session
-+ Type = xml:get_attr_s("type",Attrs),
-+ StreamStart =
-+ case xml:get_attr_s("xmpp:restart",Attrs) of
-+ "true" ->
-+ true;
-+ _ ->
-+ false
-+ end,
-+ Wait = ?MAX_WAIT,
-+ Hold = (?MAX_REQUESTS - 1),
-+ if
-+ (Type == "terminate") ->
-+ %% terminate session
-+ InPacket = Packet ++ "</stream:stream>";
-+ true ->
-+ InPacket = Packet
-+ end,
-+ ID1
-+ end,
-+%% ?DEBUG("~n InPacket: ~s ~n", [InPacket]),
-+ case http_put(ID, RID, Key, NewKey, Hold, InPacket, StreamStart) of
-+ {error, not_exists} ->
-+ ?DEBUG("no session associated with sid: ~p", [ID]),
-+ {404, [?BAD_REQUEST], ""};
-+ {error, bad_key} ->
-+ ?DEBUG("bad key: ~s", [Key]),
-+ case mnesia:dirty_read({http_bind, ID}) of
-+ [] ->
-+ {404, [?BAD_REQUEST], ""};
-+ [#http_bind{pid = FsmRef}] ->
-+ gen_fsm:sync_send_all_state_event(FsmRef,stop),
-+ {404, [?BAD_REQUEST], ""}
-+ end;
-+ {error, polling_too_frequently} ->
-+ ?DEBUG("polling too frequently: ~p", [ID]),
-+ case mnesia:dirty_read({http_bind, ID}) of
-+ [] -> %% unlikely! (?)
-+ {404, [?BAD_REQUEST], ""};
-+ [#http_bind{pid = FsmRef}] ->
-+ gen_fsm:sync_send_all_state_event(FsmRef,stop),
-+ {403, [?BAD_REQUEST], ""}
-+ end;
-+ {repeat, OutPacket} ->
-+ ?DEBUG("http_put said 'repeat!' ...~nOutPacket: ~p",
-+ [OutPacket]),
-+ send_outpacket(ID, OutPacket);
-+ ok ->
-+ receive_loop(ID,ID1,RID,Wait,Hold,Attrs)
-+ end
-+ end;
-+ _ ->
-+ {400, [?BAD_REQUEST], ""}
-+ end;
-+process_request(_Request) ->
-+ {400, [], {xmlelement, "h1", [],
-+ [{xmlcdata, "400 Bad Request"}]}}.
-+
-+receive_loop(ID,ID1,RID,Wait,Hold,Attrs) ->
-+ receive
-+ after 100 -> ok
-+ end,
-+ prepare_response(ID,ID1,RID,Wait,Hold,Attrs).
-+
-+prepare_response(ID,ID1,RID,Wait,Hold,Attrs) ->
-+ case http_get(ID,RID) of
-+ {error, not_exists} ->
-+ ?DEBUG("no session associated with sid: ~s", ID),
-+ {404, [?BAD_REQUEST], ""};
-+ {ok, keep_on_hold} ->
-+ receive_loop(ID,ID1,RID,Wait,Hold,Attrs);
-+ {ok, cancel} ->
-+ %% actually it would be better if we could completely
-+ %% cancel this request, but then we would have to hack
-+ %% ejabberd_http and I'm too lazy now
-+ {404, [?BAD_REQUEST], ""};
-+ {ok, OutPacket} ->
-+ ?DEBUG("OutPacket: ~s", [OutPacket]),
-+ if
-+ ID == ID1 ->
-+ send_outpacket(ID, OutPacket);
-+ true ->
-+ To = xml:get_attr_s("to",Attrs),
-+ OutEls = case xml_stream:parse_element(
-+ OutPacket++"</stream:stream>") of
-+ El when element(1, El) == xmlelement ->
-+ {xmlelement, _, OutAttrs, Els} = El,
-+ AuthID = xml:get_attr_s("id", OutAttrs),
-+ StreamError = false,
-+ case Els of
-+ [] ->
-+ [];
-+ [{xmlelement, "stream:features", StreamAttribs, StreamEls} | StreamTail] ->
-+ [{xmlelement, "stream:features", [{"xmlns:stream","http://etherx.jabber.org/streams"}] ++ StreamAttribs, StreamEls}] ++ StreamTail;
-+ Xml ->
-+ Xml
-+ end;
-+ {error, _} ->
-+ AuthID = "",
-+ StreamError = true,
-+ []
-+ end,
-+ if
-+ To == "" ->
-+ {200, [?CT], "<body type='terminate' "
-+ "condition='improper-addressing' "
-+ "xmlns='http://jabber.org/protocol/httpbind'/>"};
-+ StreamError == true ->
-+ {200, [?CT], "<body type='terminate' "
-+ "condition='host-unknown' "
-+ "xmlns='http://jabber.org/protocol/httpbind'/>"};
-+ true ->
-+ {200, [?CT],
-+ xml:element_to_string(
-+ {xmlelement,"body",
-+ [{"xmlns",
-+ "http://jabber.org/protocol/httpbind"},
-+ {"sid",ID},
-+ {"wait", integer_to_list(Wait)},
-+ {"requests", integer_to_list(Hold+1)},
-+ {"inactivity",
-+ integer_to_list(trunc(?MAX_INACTIVITY/1000))},
-+ {"polling", ?MIN_POLLING},
-+ {"authid", AuthID}
-+ ],OutEls})}
-+ end
-+ end
-+ end.
-+
-+send_outpacket(ID, OutPacket) ->
-+ case OutPacket of
-+ "" ->
-+ {200, [?CT], "<body xmlns='http://jabber.org/protocol/httpbind'/>"};
-+ "</stream:stream>" ->
-+ case mnesia:dirty_read({http_bind, ID}) of
-+ [#http_bind{pid = FsmRef}] ->
-+ gen_fsm:sync_send_all_state_event(FsmRef,stop)
-+ end,
-+ {200, [?CT], "<body xmlns='http://jabber.org/protocol/httpbind'/>"};
-+ _ ->
-+ case xml_stream:parse_element("<body>"
-+ ++ OutPacket
-+ ++ "</body>")
-+ of
-+ El when element(1, El) == xmlelement ->
-+ {xmlelement, _, _, OEls} = El,
-+ TypedEls = [xml:replace_tag_attr("xmlns",
-+ "jabber:client",OEl) ||
-+ OEl <- OEls],
-+ ?DEBUG(" --- outgoing data --- ~n~s~n --- END --- ~n",
-+ [xml:element_to_string(
-+ {xmlelement,"body",
-+ [{"xmlns",
-+ "http://jabber.org/protocol/httpbind"}],
-+ TypedEls})]
-+ ),
-+ {200, [?CT],
-+ xml:element_to_string(
-+ {xmlelement,"body",
-+ [{"xmlns",
-+ "http://jabber.org/protocol/httpbind"}],
-+ TypedEls})};
-+ {error, _E} ->
-+ OutEls = case xml_stream:parse_element(
-+ OutPacket++"</stream:stream>") of
-+ SEl when element(1, SEl) == xmlelement ->
-+ {xmlelement, _, _OutAttrs, SEls} = SEl,
-+ StreamError = false,
-+ case SEls of
-+ [] ->
-+ [];
-+ [{xmlelement, "stream:features", StreamAttribs, StreamEls} | StreamTail] ->
-+ TypedTail = [xml:replace_tag_attr("xmlns",
-+ "jabber:client",OEl) ||
-+ OEl <- StreamTail],
-+ [{xmlelement, "stream:features", [{"xmlns:stream","http://etherx.jabber.org/streams"}] ++ StreamAttribs, StreamEls}] ++ TypedTail;
-+ Xml ->
-+ Xml
-+ end;
-+ {error, _} ->
-+ StreamError = true,
-+ []
-+ end,
-+ if
-+ StreamError ->
-+ StreamErrCond = case xml_stream:parse_element(
-+ "<stream:stream>"++OutPacket) of
-+ El when element(1, El) == xmlelement ->
-+ {xmlelement, _Tag, _Attr, Els} = El,
-+ [{xmlelement, SE, _, Cond} | _] = Els,
-+ if
-+ SE == "stream:error" ->
-+ Cond;
-+ true ->
-+ null
-+ end;
-+ {error, _E} ->
-+ null
-+ end,
-+ case mnesia:dirty_read({http_bind, ID}) of
-+ [#http_bind{pid = FsmRef}] ->
-+ gen_fsm:sync_send_all_state_event(FsmRef,stop);
-+ _ ->
-+ err %% hu?
-+ end,
-+ case StreamErrCond of
-+ null ->
-+ {200, [?CT],
-+ "<body type='terminate' "
-+ "condition='internal-server-error' "
-+ "xmlns='http://jabber.org/protocol/httpbind'/>"};
-+ _ ->
-+ {200, [?CT],
-+ "<body type='terminate' "
-+ "condition='remote-stream-error' "
-+ "xmlns='http://jabber.org/protocol/httpbind'>" ++
-+ elements_to_string(StreamErrCond) ++
-+ "</body>"}
-+ end;
-+ true ->
-+ {200, [?CT],
-+ xml:element_to_string(
-+ {xmlelement,"body",
-+ [{"xmlns",
-+ "http://jabber.org/protocol/httpbind"}],
-+ OutEls})}
-+ end
-+ end
-+ end.
-+
-+%%%----------------------------------------------------------------------
-+%%% Callback functions from gen_fsm
-+%%%----------------------------------------------------------------------
-+
-+%%----------------------------------------------------------------------
-+%% Func: init/1
-+%% Returns: {ok, StateName, StateData} |
-+%% {ok, StateName, StateData, Timeout} |
-+%% ignore |
-+%% {stop, StopReason}
-+%%----------------------------------------------------------------------
-+init([ID, Key]) ->
-+ ?INFO_MSG("started: ~p", [{ID, Key}]),
-+ Opts = [], % TODO
-+ {ok, C2SPid} = ejabberd_c2s:start({?MODULE, {http_bind, self()}}, Opts),
-+ ejabberd_c2s:become_controller(C2SPid),
-+ Timer = erlang:start_timer(?MAX_INACTIVITY, self(), []),
-+ {ok, loop, #state{id = ID,
-+ key = Key,
-+ timer = Timer}}.
-+
-+%%----------------------------------------------------------------------
-+%% Func: StateName/2
-+%% Returns: {next_state, NextStateName, NextStateData} |
-+%% {next_state, NextStateName, NextStateData, Timeout} |
-+%% {stop, Reason, NewStateData}
-+%%----------------------------------------------------------------------
-+
-+
-+%%----------------------------------------------------------------------
-+%% Func: StateName/3
-+%% Returns: {next_state, NextStateName, NextStateData} |
-+%% {next_state, NextStateName, NextStateData, Timeout} |
-+%% {reply, Reply, NextStateName, NextStateData} |
-+%% {reply, Reply, NextStateName, NextStateData, Timeout} |
-+%% {stop, Reason, NewStateData} |
-+%% {stop, Reason, Reply, NewStateData}
-+%%----------------------------------------------------------------------
-+%state_name(Event, From, StateData) ->
-+% Reply = ok,
-+% {reply, Reply, state_name, StateData}.
-+
-+%%----------------------------------------------------------------------
-+%% Func: handle_event/3
-+%% Returns: {next_state, NextStateName, NextStateData} |
-+%% {next_state, NextStateName, NextStateData, Timeout} |
-+%% {stop, Reason, NewStateData}
-+%%----------------------------------------------------------------------
-+handle_event(_Event, StateName, StateData) ->
-+ {next_state, StateName, StateData}.
-+
-+%%----------------------------------------------------------------------
-+%% Func: handle_sync_event/4
-+%% Returns: {next_state, NextStateName, NextStateData} |
-+%% {next_state, NextStateName, NextStateData, Timeout} |
-+%% {reply, Reply, NextStateName, NextStateData} |
-+%% {reply, Reply, NextStateName, NextStateData, Timeout} |
-+%% {stop, Reason, NewStateData} |
-+%% {stop, Reason, Reply, NewStateData}
-+%%----------------------------------------------------------------------
-+handle_sync_event({send, Packet}, _From, StateName, StateData) ->
-+ Output = [StateData#state.output | Packet],
-+ Reply = ok,
-+ {reply, Reply, StateName, StateData#state{output = Output}};
-+
-+handle_sync_event(activate, From, StateName, StateData) ->
-+ case StateData#state.input of
-+ "" ->
-+ {reply, ok, StateName, StateData#state{
-+ waiting_input = From}};
-+ Input ->
-+ From ! {tcp, {http_bind, self()}, list_to_binary(Input)},
-+ {reply, ok, StateName, StateData#state{
-+ input = "",
-+ waiting_input = false,
-+ last_receiver = From}}
-+ end;
-+
-+handle_sync_event(stop, _From, _StateName, StateData) ->
-+ Reply = ok,
-+ {stop, normal, Reply, StateData};
-+
-+handle_sync_event({http_put, RID, Key, NewKey, Hold, Packet, StartTo},
-+ _From, StateName, StateData) ->
-+ %% check if RID valid
-+ RidAllow = case RID of
-+ error ->
-+ false;
-+ _ ->
-+ case StateData#state.rid of
-+ error ->
-+ %% first request - nothing saved so far
-+ true;
-+ OldRID ->
-+ ?DEBUG("state.rid/cur rid: ~p/~p",
-+ [OldRID, RID]),
-+ if
-+ (OldRID < RID) and
-+ (RID =< (OldRID + Hold + 1)) ->
-+ true;
-+ (RID =< OldRID) and
-+ (RID > OldRID - Hold - 1) ->
-+ repeat;
-+ true ->
-+ false
-+ end
-+ end
-+ end,
-+ %% check if key valid
-+ KeyAllow = case RidAllow of
-+ repeat ->
-+ true;
-+ false ->
-+ false;
-+ true ->
-+ case StateData#state.key of
-+ "" ->
-+ true;
-+ OldKey ->
-+ NextKey = httpd_util:to_lower(
-+ hex(binary_to_list(
-+ crypto:sha(Key)))),
-+ ?DEBUG("Key/OldKey/NextKey: ~s/~s/~s",
-+ [Key, OldKey, NextKey]),
-+ if
-+ OldKey == NextKey ->
-+ true;
-+ true ->
-+ ?DEBUG("wrong key: ~s",[Key]),
-+ false
-+ end
-+ end
-+ end,
-+ {_,TSec,TMSec} = now(),
-+ TNow = TSec*1000*1000 + TMSec,
-+ LastPoll = if
-+ Packet == "" ->
-+ TNow;
-+ true ->
-+ 0
-+ end,
-+ {MinPoll, _} = string:to_integer(?MIN_POLLING),
-+ if
-+ (Packet == "") and
-+ (TNow - StateData#state.last_poll < MinPoll*1000*1000) ->
-+ Reply = {error, polling_too_frequently},
-+ {reply, Reply, StateName, StateData};
-+ KeyAllow ->
-+ case RidAllow of
-+ false ->
-+ Reply = {error, not_exists},
-+ {reply, Reply, StateName, StateData};
-+ repeat ->
-+ ?DEBUG("REPEATING ~p", [RID]),
-+ [Out | _XS] = [El#hbr.out ||
-+ El <- StateData#state.req_list,
-+ El#hbr.rid == RID],
-+ case Out of
-+ [[] | OutPacket] ->
-+ Reply = {repeat, OutPacket};
-+ _ ->
-+ Reply = {repeat, Out}
-+ end,
-+ {reply, Reply, StateName,
-+ StateData#state{input = "cancel", last_poll = LastPoll}};
-+ true ->
-+ SaveKey = if
-+ NewKey == "" ->
-+ Key;
-+ true ->
-+ NewKey
-+ end,
-+ ?DEBUG(" -- SaveKey: ~s~n", [SaveKey]),
-+
-+ %% save request
-+ ReqList = [#hbr{rid=RID,
-+ key=StateData#state.key,
-+ in=StateData#state.input,
-+ out=StateData#state.output
-+ } |
-+ [El || El <- StateData#state.req_list,
-+ El#hbr.rid < RID,
-+ El#hbr.rid > (RID - 1 - Hold)]
-+ ],
-+%% ?DEBUG("reqlist: ~p", [ReqList]),
-+ case StateData#state.waiting_input of
-+ false ->
-+ cancel_timer(StateData#state.timer),
-+ Timer = erlang:start_timer(
-+ ?MAX_INACTIVITY, self(), []),
-+ Input = Packet ++ [StateData#state.input],
-+ Reply = ok,
-+ {reply, Reply, StateName,
-+ StateData#state{input = Input,
-+ rid = RID,
-+ key = SaveKey,
-+ ctime = TNow,
-+ timer = Timer,
-+ last_poll = LastPoll,
-+ req_list = ReqList
-+ }};
-+ {Receiver, _Tag} ->
-+ SendPacket =
-+ if
-+ StartTo /= "" ->
-+ ["<stream:stream to='",
-+ StartTo,
-+ "' xmlns='jabber:client' "
-+ "version='1.0' "
-+ "xmlns:stream='http://etherx.jabber.org/streams'>"] ++ Packet;
-+ true ->
-+ Packet
-+ end,
-+ ?DEBUG("really sending now: ~s", [SendPacket]),
-+ Receiver ! {tcp, {http_bind, self()},
-+ list_to_binary(SendPacket)},
-+ cancel_timer(StateData#state.timer),
-+ Timer = erlang:start_timer(
-+ ?MAX_INACTIVITY, self(), []),
-+ Reply = ok,
-+ {reply, Reply, StateName,
-+ StateData#state{waiting_input = false,
-+ last_receiver = Receiver,
-+ input = "",
-+ rid = RID,
-+ key = SaveKey,
-+ ctime = TNow,
-+ timer = Timer,
-+ last_poll = LastPoll,
-+ req_list = ReqList
-+ }}
-+ end
-+ end;
-+ true ->
-+ Reply = {error, bad_key},
-+ {reply, Reply, StateName, StateData}
-+ end;
-+
-+handle_sync_event({http_get, RID, Wait, Hold}, _From, StateName, StateData) ->
-+ {_,TSec,TMSec} = now(),
-+ TNow = TSec*1000*1000 + TMSec,
-+ cancel_timer(StateData#state.timer),
-+ Timer = erlang:start_timer(?MAX_INACTIVITY, self(), []),
-+ if
-+ (Hold > 0) and
-+ (StateData#state.output == "") and
-+ ((TNow - StateData#state.ctime) < (Wait*1000*1000)) and
-+ (StateData#state.rid == RID) and
-+ (StateData#state.input /= "cancel") ->
-+ Output = StateData#state.output,
-+ ReqList = StateData#state.req_list,
-+ Reply = {ok, keep_on_hold};
-+ (StateData#state.input == "cancel") ->
-+ Output = StateData#state.output,
-+ ReqList = StateData#state.req_list,
-+ Reply = {ok, cancel};
-+ true ->
-+ case StateData#state.output of
-+ [[]| OutPacket] ->
-+ Reply = {ok, OutPacket};
-+ _ ->
-+ Reply = {ok, StateData#state.output}
-+ end,
-+ %% save request
-+ ReqList = [#hbr{rid=RID,
-+ key=StateData#state.key,
-+ in=StateData#state.input,
-+ out=StateData#state.output
-+ } |
-+ [El || El <- StateData#state.req_list,
-+ El#hbr.rid /= RID ]
-+ ],
-+ Output = ""
-+ end,
-+ {reply, Reply, StateName, StateData#state{
-+ input = "",
-+ output = Output,
-+ timer = Timer,
-+ req_list = ReqList}};
-+
-+handle_sync_event(_Event, _From, StateName, StateData) ->
-+ Reply = ok,
-+ {reply, Reply, StateName, StateData}.
-+
-+code_change(_OldVsn, StateName, StateData, _Extra) ->
-+ {ok, StateName, StateData}.
-+
-+%%----------------------------------------------------------------------
-+%% Func: handle_info/3
-+%% Returns: {next_state, NextStateName, NextStateData} |
-+%% {next_state, NextStateName, NextStateData, Timeout} |
-+%% {stop, Reason, NewStateData}
-+%%----------------------------------------------------------------------
-+handle_info({timeout, Timer, _}, _StateName,
-+ #state{timer = Timer} = StateData) ->
-+ ?DEBUG("ding dong", []),
-+ {stop, normal, StateData};
-+
-+handle_info(_, StateName, StateData) ->
-+ {next_state, StateName, StateData}.
-+
-+%%----------------------------------------------------------------------
-+%% Func: terminate/3
-+%% Purpose: Shutdown the fsm
-+%% Returns: any
-+%%----------------------------------------------------------------------
-+terminate(_Reason, _StateName, StateData) ->
-+ ?DEBUG("terminate: deleting session ~s", [StateData#state.id]),
-+ mnesia:transaction(
-+ fun() ->
-+ mnesia:delete({http_bind, StateData#state.id})
-+ end),
-+ case StateData#state.waiting_input of
-+ false ->
-+ case StateData#state.last_receiver of
-+ undefined -> ok;
-+ Receiver -> Receiver ! {tcp_closed, {http_bind, self()}}
-+ end;
-+ {Receiver, _Tag} -> Receiver ! {tcp_closed, {http_bind, self()}}
-+ end,
-+ ok.
-+
-+%%%----------------------------------------------------------------------
-+%%% Internal functions
-+%%%----------------------------------------------------------------------
-+
-+
-+http_put(ID, RID, Key, NewKey, Hold, Packet, Restart) ->
-+ ?DEBUG("http-put",[]),
-+ case mnesia:dirty_read({http_bind, ID}) of
-+ [] ->
-+ ?DEBUG("not found",[]),
-+ {error, not_exists};
-+ [#http_bind{pid = FsmRef,to=To}] ->
-+ case Restart of
-+ true ->
-+ ?DEBUG("restart requested for ~s", [To]),
-+ gen_fsm:sync_send_all_state_event(
-+ FsmRef, {http_put, RID, Key, NewKey, Hold, Packet, To});
-+ _ ->
-+ gen_fsm:sync_send_all_state_event(
-+ FsmRef, {http_put, RID, Key, NewKey, Hold, Packet, ""})
-+ end
-+ end.
-+
-+http_get(ID,RID) ->
-+ case mnesia:dirty_read({http_bind, ID}) of
-+ [] ->
-+ {error, not_exists};
-+ [#http_bind{pid = FsmRef, wait = Wait, hold = Hold}] ->
-+ gen_fsm:sync_send_all_state_event(FsmRef,
-+ {http_get, RID, Wait, Hold})
-+ end.
-+
-+
-+parse_request(Data) ->
-+ ?DEBUG("--- incoming data --- ~n~s~n --- END --- ",
-+ [Data]),
-+ case xml_stream:parse_element(Data) of
-+ El when element(1, El) == xmlelement ->
-+ {xmlelement, Name, Attrs, Els} = El,
-+ ID = xml:get_attr_s("sid",Attrs),
-+ {RID,_X} = string:to_integer(xml:get_attr_s("rid",Attrs)),
-+ Key = xml:get_attr_s("key",Attrs),
-+ NewKey = xml:get_attr_s("newkey",Attrs),
-+ Xmlns = xml:get_attr_s("xmlns",Attrs),
-+ lists:map(fun(E) ->
-+ EXmlns = xml:get_tag_attr_s("xmlns",E),
-+ if
-+ EXmlns == "jabber:client" ->
-+ xml:remove_tag_attr("xmlns",E);
-+ true ->
-+ ok
-+ end
-+ end, Els),
-+ Packet = [xml:element_to_string(E) || E <- Els],
-+ ?DEBUG("ns fixed packet(s): ~s", [Packet]),
-+ if
-+ Name /= "body" ->
-+ {error, bad_request};
-+ Xmlns /= "http://jabber.org/protocol/httpbind" ->
-+ {error, bad_request};
-+ true ->
-+ {ok, ID, RID, Key, NewKey, Attrs, Packet}
-+ end;
-+ {error, _Reason} ->
-+ {error, bad_request}
-+ end.
-+
-+cancel_timer(Timer) ->
-+ erlang:cancel_timer(Timer),
-+ receive
-+ {timeout, Timer, _} ->
-+ ok
-+ after 0 ->
-+ ok
-+ end.
-+
-+hex(Bin) when binary(Bin) -> hex(binary_to_list(Bin));
-+hex([]) -> "";
-+hex([H|T]) ->
-+ [A,B] = if
-+ H == 0 -> "00";
-+ H < 16 -> [$0,element(H,{$1,$2,$3,$4,$5,$6,$7,$8,$9,$a,$b,$c,$d,$e,$f})];
-+ true -> erlang:integer_to_list(H,16)
-+ end,
-+ [A,B|hex(T)].
-+
-+elements_to_string([]) ->
-+ [];
-+elements_to_string([El | Els]) ->
-+ xml:element_to_string(El) ++ elements_to_string(Els).
-Index: src/web/ejabberd_web.erl
-===================================================================
---- src/web/ejabberd_web.erl (Revision 565)
-+++ src/web/ejabberd_web.erl (Arbeitskopie)
-@@ -49,7 +49,7 @@
- {"value", Value}])).
-
-
--process_get({_, true},
-+process_get({_, _, true},
- #request{auth = Auth,
- path = ["admin", "server", SHost | RPath],
- q = Query,
-@@ -94,7 +94,7 @@
- {404, [], make_xhtml([?XC("h1", "Not found")])}
- end;
-
--process_get({_, true},
-+process_get({_, _, true},
- #request{auth = Auth,
- path = ["admin" | RPath],
- q = Query,
-@@ -133,12 +133,19 @@
- [{xmlcdata, "401 Unauthorized"}]}])}
- end;
-
--process_get({true, _},
-+process_get({true, _, _},
- #request{path = ["http-poll" | RPath],
- q = _Query,
- lang = _Lang} = Request) ->
- ejabberd_http_poll:process_request(Request#request{path = RPath});
-
-+process_get({_, true, _},
-+ #request{us = _US,
-+ path = ["http-bind" | RPath],
-+ q = _Query,
-+ lang = _Lang} = Request) ->
-+ ejabberd_http_bind:process_request(Request#request{path = RPath});
-+
- process_get(_, _Request) ->
- {404, [], make_xhtml([?XC("h1", "Not found")])}.
-
-Index: src/web/ejabberd_http.erl
-===================================================================
---- src/web/ejabberd_http.erl (Revision 565)
-+++ src/web/ejabberd_http.erl (Arbeitskopie)
-@@ -30,6 +30,7 @@
- request_keepalive,
- request_content_length,
- request_lang = "en",
-+ use_http_bind = false,
- use_http_poll = false,
- use_web_admin = false,
- end_of_request = false,
-@@ -70,15 +71,17 @@
- _ ->
- ok
- end,
-+ UseHTTPBind = lists:member(http_bind, Opts),
- UseHTTPPoll = lists:member(http_poll, Opts),
- UseWebAdmin = lists:member(web_admin, Opts),
-- ?DEBUG("S: ~p~n", [{UseHTTPPoll, UseWebAdmin}]),
-+ ?DEBUG("S: ~p~n", [{UseHTTPPoll, UseHTTPBind, UseWebAdmin}]),
- ?INFO_MSG("started: ~p", [{SockMod1, Socket1}]),
- {ok, proc_lib:spawn_link(ejabberd_http,
- receive_headers,
- [#state{sockmod = SockMod1,
- socket = Socket1,
- use_http_poll = UseHTTPPoll,
-+ use_http_bind = UseHTTPBind,
- use_web_admin = UseWebAdmin}])}.
-
-
-@@ -185,6 +188,7 @@
- #state{sockmod = SockMod,
- socket = Socket,
- use_http_poll = State#state.use_http_poll,
-+ use_http_bind = State#state.use_http_bind,
- use_web_admin = State#state.use_web_admin};
- _ ->
- #state{end_of_request = true}
-@@ -200,6 +204,7 @@
- request_auth = Auth,
- request_lang = Lang,
- use_http_poll = UseHTTPPoll,
-+ use_http_bind = UseHTTPBind,
- use_web_admin = UseWebAdmin} = State) ->
- case (catch url_decode_q_split(Path)) of
- {'EXIT', _} ->
-@@ -217,7 +222,7 @@
- q = LQuery,
- auth = Auth,
- lang = Lang},
-- case ejabberd_web:process_get({UseHTTPPoll, UseWebAdmin},
-+ case ejabberd_web:process_get({UseHTTPPoll, UseHTTPBind, UseWebAdmin},
- Request) of
- El when element(1, El) == xmlelement ->
- make_xhtml_output(State, 200, [], El);
-@@ -240,6 +245,7 @@
- sockmod = SockMod,
- socket = Socket,
- use_http_poll = UseHTTPPoll,
-+ use_http_bind = UseHTTPBind,
- use_web_admin = UseWebAdmin} = State)
- when is_integer(Len) ->
- case SockMod of
-@@ -267,7 +273,7 @@
- auth = Auth,
- data = Data,
- lang = Lang},
-- case ejabberd_web:process_get({UseHTTPPoll, UseWebAdmin},
-+ case ejabberd_web:process_get({UseHTTPPoll, UseHTTPBind, UseWebAdmin},
- Request) of
- El when element(1, El) == xmlelement ->
- make_xhtml_output(State, 200, [], El);
-Index: src/xml.erl
-===================================================================
---- src/xml.erl (Revision 565)
-+++ src/xml.erl (Arbeitskopie)
-@@ -18,6 +18,7 @@
- get_tag_attr/2, get_tag_attr_s/2,
- get_subtag/2,
- get_path_s/2,
-+ remove_tag_attr/2,
- replace_tag_attr/3]).
-
- %element_to_string(El) ->
-@@ -224,6 +225,14 @@
- get_path_s(El, [cdata]) ->
- get_tag_cdata(El).
-
-+remove_tag_attr(Attr, El) ->
-+ case El of
-+ {xmlelement, Name, Attrs, Els} ->
-+ Attrs1 = lists:keydelete(Attr, 1, Attrs),
-+ {xmlelement, Name, Attrs1, Els};
-+ _ ->
-+ El
-+ end.
-
- replace_tag_attr(Attr, Value, {xmlelement, Name, Attrs, Els}) ->
- Attrs1 = lists:keydelete(Attr, 1, Attrs),
-Index: src/ejabberd_sup.erl
-===================================================================
---- src/ejabberd_sup.erl (Revision 565)
-+++ src/ejabberd_sup.erl (Arbeitskopie)
-@@ -123,6 +123,14 @@
- infinity,
- supervisor,
- [ejabberd_tmp_sup]},
-+ HTTPBindSupervisor =
-+ {ejabberd_http_bind_sup,
-+ {ejabberd_tmp_sup, start_link,
-+ [ejabberd_http_bind_sup, ejabberd_http_bind]},
-+ permanent,
-+ infinity,
-+ supervisor,
-+ [ejabberd_tmp_sup]},
- IQSupervisor =
- {ejabberd_iq_sup,
- {ejabberd_tmp_sup, start_link,
-@@ -145,6 +153,7 @@
- ServiceSupervisor,
- HTTPSupervisor,
- HTTPPollSupervisor,
-+ HTTPBindSupervisor,
- IQSupervisor,
- Listener]}}.
-
diff --git a/net-im/ejabberd/files/mod_archive.erl b/net-im/ejabberd/files/mod_archive.erl
deleted file mode 100644
index 88f0c8a7..00000000
--- a/net-im/ejabberd/files/mod_archive.erl
+++ /dev/null
@@ -1,695 +0,0 @@
-%%%----------------------------------------------------------------------
-%%% File : mod_archive.erl
-%%% Author : Olivier Goffart <ogoffar@kde.org>
-%%% Purpose : Message Archiving (JEP-0136)
-%%% Created : 19 Aug 2006
-%%%----------------------------------------------------------------------
-
-%% Version 0.0.1 2006-08-19
-%% Version 0.0.2 2006-08-21
-%% Version 0.0.3 2006-08-22
-
-
-%% Options:
-%% save_default -> true | false if messages are stored by default or not
-%% session_duration -> time in secondes before the timeout of a session
-
-
--module(mod_archive).
--author('ogoffart@kde.org').
-
--vsn('0.0.3.5').
--behaviour(gen_mod).
-
--export([start/2, stop/1, loop/3 ,
- remove_user/2, send_packet/3, receive_packet/4,
- process_iq/3, process_local_iq/3]).
-
--include("ejabberd.hrl").
--include("jlib.hrl").
-
-
--define(PROCNAME, ejabberd_mod_archive).
--define(NS_ARCHIVE, "http://jabber.org/protocol/archive").
--define(INFINITY, calendar:datetime_to_gregorian_seconds({{2038,1,19},{0,0,0}}) ).
-
--define(MYDEBUG(Format, Args), io:format("D(~p:~p:~p) : "++Format++"~n",
- [calendar:local_time(),?MODULE,?LINE]++Args)).
-
-
-%NOTE i was not sure what format to adopt for archive_option. otr_list is unused
--record(archive_options, {us, default=unset , save_list = [] , nosave_list =[] , otr_list = [] }).
-%-record(archive_options, {usj, us , jid , type , value}).
--record(archive_message, { usjs , us , jid , start , message_list=[] , subject=""}).
--record(msg , {dirrection , secs, body }).
-
-start(Host, Opts) ->
- IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
- Save_Default = gen_mod:get_opt(save_default, Opts, false),
- Session_Duration = gen_mod:get_opt(session_duration, Opts, 1300),
- mnesia:create_table(archive_options,[{disc_copies, [node()]}, {attributes, record_info(fields, archive_options)}]),
- mnesia:create_table(archive_message,[{disc_copies, [node()]}, {attributes, record_info(fields, archive_message)}]),
-% mnesia:add_table_index(archive_options, us),
- mnesia:add_table_index(archive_message, us),
- ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 50),
- gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_ARCHIVE, ?MODULE, process_iq, IQDisc),
- gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_ARCHIVE, ?MODULE, process_local_iq, IQDisc),
- ejabberd_hooks:add(user_send_packet, Host, ?MODULE, send_packet, 90),
- ejabberd_hooks:add(user_receive_packet, Host, ?MODULE, receive_packet, 90),
- catch mod_disco:register_feature(Host, ?NS_ARCHIVE ++ "#manage"),
- catch mod_disco:register_feature(Host, ?NS_ARCHIVE ++ "#save"),
- catch mod_disco:register_feature(Host, ?NS_ARCHIVE ++ "#manual"),
- register(gen_mod:get_module_proc(Host, ?PROCNAME), spawn(?MODULE, loop, [Host, [], { Save_Default, Session_Duration }])).
-
-stop(Host) ->
- ejabberd_hooks:delete(remove_user, Host, ?MODULE, remove_user, 50),
- gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_ARCHIVE),
- gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_ARCHIVE),
- ejabberd_hooks:delete(user_send_packet, Host, ?MODULE, send_packet, 90),
- ejabberd_hooks:delete(user_receive_packet, Host, ?MODULE, receive_packet, 90),
- catch mod_disco:unregister_feature(Host, ?NS_ARCHIVE ++ "#manage"),
- catch mod_disco:unregister_feature(Host, ?NS_ARCHIVE ++ "#save"),
- catch mod_disco:unregister_feature(Host, ?NS_ARCHIVE ++ "#manual"),
- Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
- Proc ! stop,
- {wait, Proc}.
-
-
-%Workarounf the fact that if the client send <iq type='get'> it end up like <iq type='get' from='u@h' to = 'u@h'>
-process_iq(From, To, IQ) ->
- #iq{sub_el = SubEl} = IQ,
- #jid{lserver = LServer, luser = LUser} = To,
- #jid{luser = FromUser} = From,
- case {LUser , LServer , lists:member(LServer, ?MYHOSTS)} of
- { FromUser , _ , true } ->
- process_local_iq(From, To, IQ);
- { "" , _ , true } ->
- process_local_iq(From, To, IQ);
- { "" , "" , _ } ->
- process_local_iq(From, To, IQ);
- _ ->
- IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}
- end.
-
-process_local_iq(From, To, #iq{sub_el = SubEl} = IQ) ->
- case lists:member(From#jid.lserver, ?MYHOSTS) of
- false ->
- IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
- true ->
- {xmlelement, Name, _Attrs, _Els} = SubEl,
- case Name of
- "save" -> process_local_iq_save( From, To , IQ ) ;
-% "otr" -> process_local_iq_otr( From, To , IQ ) ;
- "list" -> process_local_iq_list( From , To , IQ ) ;
- "retrieve" -> process_local_iq_retrieve( From , To , IQ );
- "store" -> process_local_iq_store( From , To , IQ );
- "remove" -> process_local_iq_remove( From , To , IQ );
- _ -> IQ#iq{type = error, sub_el = [SubEl, ?ERR_FEATURE_NOT_IMPLEMENTED]}
- end
- end.
-
-
-remove_user(User, Server) ->
- LUser = jlib:nodeprep(User),
- LServer = jlib:nameprep(Server),
- US = {LUser, LServer},
- F = fun() ->
- lists:foreach(fun(R) ->
- mnesia:delete_object(R)
- end,
- mnesia:index_read(archive_message, US, #archive_message.us))
- end,
- mnesia:transaction(F),
- F1 = fun() ->
- mnesia:delete({archive_options, US})
- end,
- mnesia:transaction(F1).
-
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% 3 Automated archiving
-%%
-
-send_packet(From, To, P) ->
- Host = From#jid.lserver,
- Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
- Proc ! {addlog, {to, From#jid.luser, Host , To, P}}.
-
-receive_packet(_JID, From, To, P) ->
- Host = To#jid.lserver,
- Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
- Proc ! {addlog, {from, To#jid.luser, Host , From, P}}.
-
-
-% storage loop. Storages is a list containing 'open' storage element
-% storage element are in the form: { Timestamp , { LUser , LServer , Jid , Start } }
-loop(Host , Storages, { Save_Default, Session_Duration } ) ->
- receive
- {addlog, { Dirrection , LUser , LServer , Jid , P }} ->
- NStorages = case catch should_store_jid( LUser , LServer , Jid , Save_Default) of
- false -> Storages;
- true ->
- case parse_message(P) of
- ignore -> Storages;
- Body -> catch do_log( Storages , LUser, LServer, Jid , Dirrection, Body , Session_Duration )
- end
- end,
- loop(Host, NStorages, { Save_Default, Session_Duration });
- {get_save_default, Pid} ->
- Pid ! Save_Default,
- loop(Host, Storages, { Save_Default, Session_Duration });
- stop ->
- ok;
- _ ->
- loop(Host, Storages, { Save_Default, Session_Duration })
- end.
-
-
-
-% parce a message and return the body string if sicessfull, return ignore if the message should not be stored
-parse_message({xmlelement , "message" , _ , _ } = Packet) ->
- case xml:get_subtag(Packet, "body") of
- false -> ignore;
- Body_xml ->
- case xml:get_tag_attr_s("type", Packet) of
- "groupchat" -> ignore ;
- _ -> xml:get_tag_cdata(Body_xml)
- end
- end;
-parse_message(_) -> ignore.
-
-% archive the message Body return the list of new Storages
-% Storages: a list of open storages key (usjs)
-% LUser , LServer : the local user's information
-% Jid : the contact's jid
-% Body : the message body
-do_log( Storages, LUser, LServer, Jid , Dirrection, Body , Session_Duration ) ->
- NStorages = smart_find_storage( LUser , LServer, Jid , Storages , get_timestamp() + Session_Duration ),
- [{Tm , { _ , _ , _ , Start } = Key } | _ ] = NStorages,
- Message = #msg{dirrection=Dirrection , secs=(Tm-Start), body = Body },
- mnesia:transaction( fun() ->
- NE = case mnesia:read({archive_message, Key }) of
- [] ->
- #archive_message{ usjs= Key ,
- us = { LUser , LServer } ,
- jid = jlib:jid_tolower(jlib:jid_remove_resource(Jid)) ,
- start = Tm ,
- message_list = [ Message ] };
- [E] -> E#archive_message{ message_list=lists:append( E#archive_message.message_list , [ Message ] ) }
- end,
- mnesia:write( NE )
- end),
- NStorages.
-
-%find a storage for Jid and move it on the begin on the storage list, if none are found, a new storage is created, old storages element are removed
-smart_find_storage( LUser, LServer, Jid , [ C | Tail ] , TimeStampLimit ) ->
- NGid=jlib:jid_remove_resource(jlib:jid_tolower(Jid)),
- case C of
- { _ , { LUser , LServer , NGid , _ } = St } ->
- [ { get_timestamp() , St } | Tail ];
- { Tm , _ } ->
- if Tm > TimeStampLimit ->
- smart_find_storage( LUser, LServer, Jid , [ ] , TimeStampLimit );
- true ->
- [ UJ | NT ] = smart_find_storage( LUser , LServer , Jid , Tail , TimeStampLimit ),
- [ UJ | [ C | NT ] ]
- end
- end;
-
-
-smart_find_storage( LUser, LServer, Jid , [ ] , _Limit ) ->
- Tm = get_timestamp() ,
- [ { Tm , { LUser, LServer , jlib:jid_tolower(jlib:jid_remove_resource(Jid)) , Tm } } ].
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% 3.1 Save Mode
-%%
-
-process_local_iq_save(From, _To, #iq{type = Type, sub_el = SubEl} = IQ) ->
- Result = case Type of
- set ->
- {xmlelement, _Name, _Attrs, Els} = SubEl,
- process_save_set(From#jid.luser , From#jid.lserver, Els);
- get ->
- process_save_get(From#jid.luser , From#jid.lserver)
- end,
- case Result of
- {result , R } ->
- IQ#iq{type = result, sub_el = [R] };
- ok ->
- broadcast_iq(From, IQ#iq{type = set, sub_el=[SubEl]}),
- IQ#iq{type = result, sub_el = [] };
- {error , E } ->
- IQ#iq{type = error, sub_el = [SubEl , E]};
- _ ->
- IQ#iq{type = error, sub_el = [SubEl , ?ERR_INTERNAL_SERVER_ERROR]}
- end.
-
-
-
-
-% return {error , xmlelement} or {result , xmlelement }
-process_save_get(LUser, LServer) ->
- case catch mnesia:dirty_read(archive_options, {LUser, LServer}) of
- {'EXIT', _Reason} ->
- {error, ?ERR_INTERNAL_SERVER_ERROR};
- [] ->
- {result, {xmlelement , "save" , [{"xmlns", ?NS_ARCHIVE}] , [default_element(LServer)]}};
- [#archive_options{default = Default, save_list = Save_list , nosave_list = Nosave_list}] ->
- LItems = lists:append(
- lists:map( fun(J) ->
- {xmlelement, "item", [{"jid", jlib:jid_to_string(J)}, {"save","true"}] , []}
- end, Save_list),
- lists:map( fun(J) ->
- {xmlelement, "item", [{"jid", jlib:jid_to_string(J)}, {"save","false"}] , []}
- end, Nosave_list) ),
- DItem = case Default of
- true ->
- {xmlelement, "default",[{"save", "true"} ], []};
- false ->
- {xmlelement, "default",[{"save", "false"} ], []};
- _ ->
- default_element(LServer)
- end,
- {result, {xmlelement , "save" , [{"xmlns", ?NS_ARCHIVE}] , [DItem | LItems] } }
- end.
-
-%return the <default save='unset' service='...' /> element
-default_element(Host) ->
- Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
- Proc ! {get_save_default , self()},
- receive
- Service ->
- {xmlelement, "default",[{"save", "unset"} , {"service" , atom_to_list(Service)}], []}
- end.
-
-
-% return {error , xmlelement} or {result , xmlelement } or ok
-process_save_set(LUser, LServer, Elms) ->
- F = fun() ->
- NE = case mnesia:read({archive_options, {LUser, LServer}}) of
- [] ->
- #archive_options{ us = { LUser , LServer } };
- [E] ->
- E
- end,
- SNE=transaction_parse_save_elem(NE,Elms),
- case SNE of
- {error , _} -> SNE;
- _ -> mnesia:write( SNE )
- end
- end,
- case mnesia:transaction(F) of
- {atomic, {error, _} = Error} ->
- Error;
- {atomic, _ } ->
- ok;
- _ -> {error, ?ERR_INTERNAL_SERVER_ERROR}
- end.
-
-
-% transaction_parse_save_elem( archive_options , ListOfXmlElement ) -> #archive_options
-% parse the list of xml element, and modify the given archive_option
-transaction_parse_save_elem(Options, [ {xmlelement , "default" , Attrs , _ } | Tail]) ->
- V = case xml:get_attr_s("save", Attrs) of
- "true" -> true;
- "false" -> false;
- _ -> unset
- end,
- transaction_parse_save_elem( Options#archive_options{default = V} , Tail );
-
-transaction_parse_save_elem(Options, [ {xmlelement , "item" , Attrs , _} | Tail]) ->
- case jlib:string_to_jid(xml:get_attr_s("jid", Attrs)) of
- error -> { error , ?ERR_JID_MALFORMED };
- #jid{luser=LUser,lserver=LServer,lresource=LResource} ->
- Jid = {LUser, LServer, LResource },
- case xml:get_attr_s("save", Attrs) of
- "true" ->
- transaction_parse_save_elem( Options#archive_options{save_list=[Jid | lists:delete(Jid,Options#archive_options.save_list) ] ,
- nosave_list=lists:delete(Jid,Options#archive_options.nosave_list)
- } , Tail );
- "false" ->
- transaction_parse_save_elem( Options#archive_options{save_list=lists:delete(Jid,Options#archive_options.save_list) ,
- nosave_list=[Jid | lists:delete(Jid,Options#archive_options.nosave_list) ]
- } , Tail );
- _ ->
- transaction_parse_save_elem( Options#archive_options{save_list=lists:delete(Jid,Options#archive_options.save_list ) ,
- nosave_list=lists:delete(Jid,Options#archive_options.nosave_list)
- } , Tail )
- end
- end;
-
-transaction_parse_save_elem(Options, [ ]) -> Options;
-transaction_parse_save_elem(Options, [ _ | Tail ]) -> transaction_parse_save_elem(Options, Tail).
-
-
-broadcast_iq(#jid{luser = User, lserver = Server}, IQ) ->
- Fun = fun(Resource) ->
- ejabberd_router:route(
- jlib:make_jid("", Server, ""),
- jlib:make_jid(User, Server, Resource),
- jlib:iq_to_xml(IQ#iq{id="push"}))
- end,
- lists:foreach(Fun, ejabberd_sm:get_user_resources(User,Server)).
-
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% 3.1 Off-the-Record Mode
-%%
-
-%TODO
-
-
-
-
-
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Utility function
-
-% Return true if LUser@LServer should log message for the contact Jid
-should_store_jid( LUser , LServer , Jid , Service_Default) ->
- case catch mnesia:dirty_read(archive_options, {LUser, LServer}) of
- [#archive_options{default = Default, save_list = Save_list , nosave_list = Nosave_list}] ->
- Jid_t = jlib:jid_tolower(Jid),
- Jid_b = jlib:jid_remove_resource(Jid_t),
- A = lists:member(Jid_t, Save_list),
- B = lists:member(Jid_t, Nosave_list),
- C = lists:member(Jid_b, Save_list),
- D = lists:member(Jid_b, Nosave_list),
- if A -> true;
- B -> false;
- C -> true;
- D -> false;
- Default == true -> true;
- Default == false -> false;
- true -> Service_Default
- end;
- _ -> Service_Default
- end.
-
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% 4. Manual Archiving
-%%
-
-
-process_local_iq_store(From, _To, #iq{type = Type, sub_el = SubEl} = IQ) ->
- #jid{luser = LUser, lserver = LServer} = From,
- case Type of
- get ->
- IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
- set ->
- case parse_store_element ( LUser, LServer, SubEl ) of
- { error , E } -> IQ#iq{type = error, sub_el = [SubEl , E ]} ;
- Collection ->
- case mnesia:transaction(fun() -> mnesia:write( Collection ) end) of
- {atomic, _ } ->
- IQ#iq{type = result , sub_el=[]};
- _ ->
- IQ#iq{type = error, sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]}
- end
- end
- end.
-
-
-
-% return a #archive_message StoreElem is an xmlelement , or return {error, E}
-parse_store_element(LUser, LServer, {xmlelement, "store" , Attrs , SubEls } ) ->
- case index_from_argument(LUser, LServer, Attrs) of
- {error , E } -> {error , E} ;
- { LUser , LServer , Jid , Start } = Index ->
- Messages = parse_store_element_sub( SubEls ) ,
- #archive_message{ usjs = Index ,
- us = { LUser, LServer} ,
- jid = Jid ,
- start = Start,
- subject = xml:get_attr_s("subject" , Attrs ) ,
- message_list = Messages }
- end.
-
-parse_store_element_sub( [ {xmlelement , Dir , _ , _ } = E | Tail ] ) ->
- [ #msg{ dirrection=list_to_atom(Dir) , secs= list_to_integer(xml:get_tag_attr_s("secs" , E)), body=xml:get_tag_cdata(xml:get_subtag(E,"body")) } |
- parse_store_element_sub( Tail ) ];
-
-parse_store_element_sub( [ ] ) -> [];
-parse_store_element_sub( [ _ | Tail ] ) -> parse_store_element_sub( Tail ).
-
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% 5. Archive Management
-%%
-
-
-process_local_iq_list(From, _To, #iq{type = Type, sub_el = SubEl} = IQ) ->
- #jid{luser = LUser, lserver = LServer} = From,
- case Type of
- set ->
- IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
- get ->
- {xmlelement, _ , Attrs, _} = SubEl,
- MaxItems = case xml:get_attr("maxitems" , Attrs) of
- false -> all;
- {value , V } -> list_to_integer(V)
- end,
- Result = case parse_root_argument(Attrs) of
- {error , E } -> {error , E};
- {interval, Start , Stop } -> get_list(LUser, LServer , Start, Stop, '_' , MaxItems);
- {interval, Start , Stop , Jid } -> get_list(LUser, LServer , Start, Stop, Jid , MaxItems);
- _ -> { error , ?ERR_BAD_REQUEST }
- end,
-
- case Result of
- {ok, Items , Partial} ->
- Zero = calendar:datetime_to_gregorian_seconds({{1970, 1, 1}, {0, 0, 0}}),
- Fun = fun(A) ->
- Seconds= A#archive_message.start-Zero,
- Start2 = jlib:now_to_utc_string( {Seconds div 1000000, Seconds rem 1000000, 0} ) ,
- Args0 = [{"with", jlib:jid_to_string(A#archive_message.jid)} , {"start" , Start2 } ] ,
- Args = case A#archive_message.subject of
- "" -> Args0;
- Subject -> [ {"subject",Subject} | Args0 ]
- end,
- {xmlelement, "store", Args , [] }
- end,
- MIA = case Partial of
- false -> [];
- true -> [{"partial" , "true"}]
- end,
- IQ#iq{type = result, sub_el = [{xmlelement, "list", [{"xmlns", ?NS_ARCHIVE} | MIA ], lists:map(Fun, lists:keysort(3, Items)) }] };
- {error, R} ->
- IQ#iq{type = error, sub_el = [SubEl , R]}
- end
- end.
-
-
-
-
-process_local_iq_retrieve(From, _To, #iq{type = Type, sub_el = SubEl} = IQ) ->
- #jid{luser = LUser, lserver = LServer} = From,
- case Type of
- set ->
- IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
- get ->
- {xmlelement, _ , Attrs , _ } = SubEl,
- case index_from_argument(LUser, LServer, Attrs ) of
- { error , E } -> IQ#iq{type = error, sub_el = [SubEl , E ]} ;
- Index ->
- case retrieve_collection( Index ) of
- {error, Err } -> IQ#iq{type = error, sub_el = [SubEl , Err]};
- Store -> IQ#iq{type = result, sub_el = [Store] }
- end
- end
- end.
-
-
-retrieve_collection(Index) ->
- case get_collection(Index) of
- {error, E} ->
- {error, E};
- A ->
- Zero = calendar:datetime_to_gregorian_seconds({{1970, 1, 1}, {0, 0, 0}}),
- Seconds = A#archive_message.start-Zero,
- Start2 = jlib:now_to_utc_string( {Seconds div 1000000, Seconds rem 1000000, 0} ) ,
- Args0 = [{"xmlns", ?NS_ARCHIVE} , {"with", jlib:jid_to_string(A#archive_message.jid)} , {"start" , Start2 } ] ,
- Args = case A#archive_message.subject of
- "" -> Args0;
- Subject -> [ Subject | Args0 ]
- end,
- Format_Fun = fun(Elem) ->
- {xmlelement, atom_to_list( Elem#msg.dirrection) ,
- [ {"secs" , integer_to_list(Elem#msg.secs) } ] ,
- [ {xmlelement , "body" , [] , [{xmlcdata, Elem#msg.body }] } ] }
- end,
- {xmlelement, "store", Args , lists:map(Format_Fun, A#archive_message.message_list ) }
- end.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% 5.3 Removing a Collection
-%%
-
-
-process_local_iq_remove(From, _To, #iq{type = Type, sub_el = SubEl} = IQ) ->
- #jid{luser = LUser, lserver = LServer} = From,
- case Type of
- get ->
- IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
- set ->
- {xmlelement, _, Attrs, _} = SubEl,
- Result = case parse_root_argument(Attrs) of
- {error , E } -> IQ#iq{type = error, sub_el = [SubEl, E ] } ;
- {interval, Start , Stop } -> process_remove_interval(LUser, LServer , Start, Stop, '_');
- {interval, Start , Stop , Jid } -> process_remove_interval(LUser, LServer , Start, Stop, Jid);
- {index , Jid, Start } -> process_remove_index({LUser, LServer , Jid, Start})
- end,
- case Result of
- { error , Ee } -> IQ#iq{type = error, sub_el = [SubEl , Ee ]} ;
- ok -> IQ#iq{type = result , sub_el=[]}
- end
- end.
-
-process_remove_index( Index ) ->
- case mnesia:transaction(fun() -> mnesia:delete({archive_message, Index}) end) of
- {atomic, _} ->
- ok;
- {aborted, _} ->
- {error, ?ERR_ITEM_NOT_FOUND}
- end.
-
-process_remove_interval(LUser, LServer , Start, End, With) ->
- Fun = fun() ->
- Pat = #archive_message{ usjs= '_' , us = { LUser, LServer } , jid= With ,
- start='$1' , message_list='_' , subject = '_' },
- Guard = [{'>=', '$1', Start},{'<', '$1', End}],
-
- lists:foreach(fun(R) -> mnesia:delete_object(R) end,
- mnesia:select(archive_message, [{Pat, Guard, ['$_']}]) )
- end,
-
- case mnesia:transaction( Fun ) of
- {atomic, _} ->
- ok;
- {aborted, _} ->
- {error, ?ERR_INTERNAL_SERVER_ERROR}
- end.
-
-
-
-% return { ok, [ { #archive_message } ] } or { error , xmlelement }
-% With is a tuple Jid, or '_'
-get_list(LUser, LServer , Start, End, With , MaxItems ) ->
- case mnesia:transaction(fun() ->
- Pat = #archive_message{ usjs= '_' , us = { LUser, LServer } , jid= With ,
- start='$1' , message_list='_' , subject = '_' },
- Guard = [{'>=', '$1', Start},{'<', '$1', End}],
- case MaxItems of
- all -> mnesia:select(archive_message, [{Pat, Guard, ['$_']}]) ;
- _ -> mnesia:select(archive_message, [{Pat, Guard, ['$_']}],MaxItems , read)
- end
-
- end) of
- {atomic, {Result, _ }} ->
- {ok, Result , true}; %FIXME: how to know if it's partial ?
- {atomic, Result} ->
- {ok, Result , false};
- {aborted, _} ->
- {error, ?ERRT_INTERNAL_SERVER_ERROR("", "plop" )}
- end.
-
-
-% Index is {LUser, LServer , With , Start}
-get_collection( Index ) ->
- case catch mnesia:dirty_read(archive_message, Index) of
- {'EXIT', _Reason} ->
- {error, ?ERR_INTERNAL_SERVER_ERROR};
- [] ->
- {error, ?ERR_ITEM_NOT_FOUND};
- [C] -> C
- end.
-
-
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Utility
-
-
-% return either {error , Err } or {LUser, LServer , Jid , Start}
-index_from_argument(LUser, LServer, Attrs ) ->
- case parse_root_argument( Attrs ) of
- { error , E } -> { error , E } ;
- { index , Jid , Start } -> {LUser, LServer , Jid , Start};
- _ -> { error, ?ERR_BAD_REQUEST }
- end.
-
-%parse commons arguments of root elements
-parse_root_argument( Attrs ) ->
- case parse_root_argument_aux(Attrs , { undefined , undefined , undefined} ) of
- {error , E } -> {error , E};
- {{ok,Jid } , {ok,Start} , undefined } -> { index , Jid , Start };
- {{ok,Jid } , undefined , undefined } -> { interval , 0 , ?INFINITY , Jid };
- {{ok,Jid } , {ok,Start} , {ok,Stop} } -> { interval , Start , Stop , Jid };
- {undefined , {ok,Start} , {ok,Stop} } -> { interval , Start , Stop };
- {undefined , undefined , undefined } -> { interval , 0 , ?INFINITY };
- _ -> {error, ?ERR_BAD_REQUEST}
- end.
-
-parse_root_argument_aux([{"with", JidStr} | Tail ] , { _ , AS , AE} ) ->
- case jlib:string_to_jid( JidStr ) of
- error -> { error , ?ERR_JID_MALFORMED };
- JidS ->
- Jid = jlib:jid_tolower(JidS),
- parse_root_argument_aux( Tail , { {ok , Jid} , AS , AE } )
- end;
-parse_root_argument_aux([{"start", Str} | Tail ] , { AW , _ , AE} ) ->
- case jlib:datetime_string_to_timestamp( Str ) of
- undefined -> { error , ?ERR_BAD_REQUEST };
- No ->
- Val = calendar:datetime_to_gregorian_seconds(calendar:now_to_datetime(No)),
- parse_root_argument_aux( Tail , { AW , {ok , Val} , AE } )
- end;
-parse_root_argument_aux([{"end", Str} | Tail ] , { AW , AS , _} ) ->
- case jlib:datetime_string_to_timestamp( Str ) of
- undefined -> { error , ?ERR_BAD_REQUEST };
- No ->
- Val = calendar:datetime_to_gregorian_seconds(calendar:now_to_datetime(No)),
- parse_root_argument_aux( Tail , { AW , AS , {ok , Val} } )
- end;
-parse_root_argument_aux([ _ | Tail ] , A ) ->
- parse_root_argument_aux( Tail , A );
-parse_root_argument_aux([ ] , A ) -> A.
-
-
-
-get_timestamp() -> calendar:datetime_to_gregorian_seconds(calendar:local_time()).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% NOTE ABOUT THE JEP-0136
-% - errors
-% * when setting <save/> , how to revert to the default, for a contact or for the default
-% * when setting <save/> , is it possible to have several element (<default/> , <item/>) i assume yes
-% * It is STRONGLY RECOMMENDED to use a bare jid. but if a full jid is used, does the resource count when doing comparison ?
-% * the name attribute of the <form/> element is missing in the shema Example 42
-% * the secs argument is required, and the utc is not there in the sheme Example 25
-% * <store/> may have partial = "true" but how to get the tail ? and how to specify the mex number
-% and before example 35 s|<list/>|<store/>|
-% * in the schema , the <remove> element has required attribute, => example 40
-% * How many time should an otr session persist ?
-%
-% - opinions
-% * I don't like the format using secs='' and why also support utc ?
-% * There is very few things to sort, only the body ? not the message type and all others elements ?
-% * There is no syncronisation mechanisme ( a way to know all element modified (added, changed, or removed) after a given date)
-% * The client should be able to disable otr support of the server (if he want the message to be logged)
-% *
-% * comment juste avoir les derniers message du contact
-
-
diff --git a/net-im/ejabberd/files/mod_irc_utf-8.patch b/net-im/ejabberd/files/mod_irc_utf-8.patch
deleted file mode 100644
index 1f09aeeb..00000000
--- a/net-im/ejabberd/files/mod_irc_utf-8.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- src/mod_irc/mod_irc.erl.ori 2006-12-21 08:38:09.000000000 +0100
-+++ src/mod_irc/mod_irc.erl 2006-12-21 08:38:29.000000000 +0100
-@@ -27,7 +27,7 @@
- -include("ejabberd.hrl").
- -include("jlib.hrl").
-
---define(DEFAULT_IRC_ENCODING, "koi8-r").
-+-define(DEFAULT_IRC_ENCODING, "utf-8").
-
- -record(irc_connection, {jid_server_host, pid}).
- -record(irc_custom, {us_host, data}).
diff --git a/net-im/ejabberd/files/mod_pep.patch b/net-im/ejabberd/files/mod_pep.patch
deleted file mode 100644
index a65a344c..00000000
--- a/net-im/ejabberd/files/mod_pep.patch
+++ /dev/null
@@ -1,2319 +0,0 @@
---- orig/src/ejabberd_sm.erl
-+++ mod/src/ejabberd_sm.erl
-@@ -353,7 +353,9 @@
- true ->
- ok
- end
-- end, PResources);
-+ end, PResources),
-+ ejabberd_hooks:run(incoming_presence_hook, LServer,
-+ [From, To, Packet]);
- true ->
- ok
- end;
---- orig/src/jlib.hrl
-+++ mod/src/jlib.hrl
-@@ -33,6 +33,7 @@
- -define(NS_PUBSUB_EVENT, "http://jabber.org/protocol/pubsub#event").
- -define(NS_PUBSUB_OWNER, "http://jabber.org/protocol/pubsub#owner").
- -define(NS_PUBSUB_NMI, "http://jabber.org/protocol/pubsub#node-meta-info").
-+-define(NS_PUBSUB_ERRORS,"http://jabber.org/protocol/pubsub#errors").
- -define(NS_COMMANDS, "http://jabber.org/protocol/commands").
-
- -define(NS_EJABBERD_CONFIG, "ejabberd:config").
---- orig/src/mod_disco.erl
-+++ mod/src/mod_disco.erl
-@@ -168,11 +168,12 @@
- end
- end.
-
--get_local_identity(_Acc, _From, _To, [], _Lang) ->
-- [{xmlelement, "identity",
-- [{"category", "server"},
-- {"type", "im"},
-- {"name", "ejabberd"}], []}];
-+get_local_identity(Acc, _From, _To, [], _Lang) ->
-+ Acc ++
-+ [{xmlelement, "identity",
-+ [{"category", "server"},
-+ {"type", "im"},
-+ {"name", "ejabberd"}], []}];
-
- get_local_identity(Acc, _From, _To, _Node, _Lang) ->
- Acc.
---- orig/src/mod_pubsub/mod_pubsub.erl
-+++ mod/src/mod_pubsub/mod_pubsub.erl
-@@ -18,13 +18,12 @@
- start/2,
- stop/1]).
-
---export([delete_item/3,
-- set_entities/4,
-- delete_node/2,
-- create_new_node/2,
-- subscribe_node/3,
-- get_node_config/4,
-- set_node_config/4]).
-+-export([incoming_presence/3]).
-+
-+-export([disco_local_identity/5,
-+ iq_pep_local/3,
-+ iq_pep_sm/3,
-+ pep_disco_items/5]).
-
- %% gen_server callbacks
- -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
-@@ -36,10 +35,13 @@
- -record(state, {host, server_host, access}).
-
- -define(DICT, dict).
-+%% XXX: this is currently a hard limit. Would be nice to have it
-+%% configurable in certain cases.
- -define(MAXITEMS, 20).
- -define(MAX_PAYLOAD_SIZE, 100000).
-
- -record(pubsub_node, {host_node, host_parent, info}).
-+-record(pep_node, {owner_node, info}). %owner is {luser, lserver, ""}
- -record(nodeinfo, {items = [],
- options = [],
- entities = ?DICT:new()
-@@ -48,10 +50,24 @@
- subscription = none}).
- -record(item, {id, publisher, payload}).
-
-+-record(pubsub_presence, {to_from, resource}).
-+%% to_from is {ToLUser, ToLServer, FromLUser, FromLServer}.
-+
-+get_node_info(#pubsub_node{info = Info}) -> Info;
-+get_node_info(#pep_node{info = Info}) -> Info.
-+
-+set_node_info(#pubsub_node{} = N, NewInfo) -> N#pubsub_node{info = NewInfo};
-+set_node_info(#pep_node{} = N, NewInfo) -> N#pep_node{info = NewInfo}.
-+
-+get_node_name(#pubsub_node{host_node = {_Host, Node}}) -> Node;
-+get_node_name(#pep_node{owner_node = {_Owner, Node}}) -> Node.
-+
- -define(PROCNAME, ejabberd_mod_pubsub).
- -define(MYJID, #jid{user = "", server = Host, resource = "",
- luser = "", lserver = Host, lresource = ""}).
-
-+-define(NS_PUBSUB_SUB_AUTH, "http://jabber.org/protocol/pubsub#subscribe_authorization").
-+
- %%====================================================================
- %% API
- %%====================================================================
-@@ -79,29 +95,9 @@
- gen_server:call(Proc, stop),
- supervisor:stop_child(ejabberd_sup, Proc).
-
--delete_item(From, Node, ItemID) ->
-- delete_item(get_host(), From, Node, ItemID).
--
--delete_node(From, Node) ->
-- delete_node(get_host(), From, Node).
--
--create_new_node(Node, From) ->
-- create_new_node(get_host(), Node, From).
--
--subscribe_node(From, JID, Node) ->
-- subscribe_node(get_host(), From, JID, Node).
--
--set_node_config(From, Node, Els, Lang) ->
-- set_node_config(get_host(), From, Node, Els, Lang).
--
--get_host() ->
-- ejabberd_mod_pubsub ! {get_host, self()},
-- receive
-- {pubsub_host, Host} ->
-- Host
-- after 5000 ->
-- timeout
-- end.
-+incoming_presence(From, #jid{lserver = Host} = To, Packet) ->
-+ Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
-+ gen_server:cast(Proc, {presence, From, To, Packet}).
-
- %%====================================================================
- %% gen_server callbacks
-@@ -118,12 +114,36 @@
- mnesia:create_table(pubsub_node,
- [{disc_only_copies, [node()]},
- {attributes, record_info(fields, pubsub_node)}]),
-+ mnesia:create_table(pep_node,
-+ [{disc_only_copies, [node()]},
-+ {attributes, record_info(fields, pep_node)}]),
-+ mnesia:create_table(pubsub_presence,
-+ [{ram_copies, [node()]},
-+ {attributes, record_info(fields, pubsub_presence)},
-+ {type, bag}]),
-+
- Host = gen_mod:get_opt(host, Opts, "pubsub." ++ ServerHost),
- update_table(Host),
- mnesia:add_table_index(pubsub_node, host_parent),
- ServedHosts = gen_mod:get_opt(served_hosts, Opts, []),
- Access = gen_mod:get_opt(access_createnode, Opts, all),
-
-+ mod_disco:register_feature(ServerHost, ?NS_PUBSUB),
-+ ejabberd_hooks:add(disco_local_identity, ServerHost, ?MODULE, disco_local_identity, 75),
-+ ejabberd_hooks:add(disco_sm_items, ServerHost, ?MODULE, pep_disco_items, 50),
-+
-+ IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
-+ gen_iq_handler:add_iq_handler(ejabberd_local, ServerHost, ?NS_PUBSUB,
-+ ?MODULE, iq_pep_local, IQDisc),
-+ gen_iq_handler:add_iq_handler(ejabberd_local, ServerHost, ?NS_PUBSUB_OWNER,
-+ ?MODULE, iq_pep_local, IQDisc),
-+ gen_iq_handler:add_iq_handler(ejabberd_sm, ServerHost, ?NS_PUBSUB,
-+ ?MODULE, iq_pep_sm, IQDisc),
-+ gen_iq_handler:add_iq_handler(ejabberd_sm, ServerHost, ?NS_PUBSUB_OWNER,
-+ ?MODULE, iq_pep_sm, IQDisc),
-+
-+ ejabberd_hooks:add(incoming_presence_hook, ServerHost, ?MODULE, incoming_presence, 50),
-+
- ejabberd_router:register_route(Host),
- create_new_node(Host, ["pubsub"], ?MYJID),
- create_new_node(Host, ["pubsub", "nodes"], ?MYJID),
-@@ -132,8 +152,6 @@
- lists:foreach(fun(H) ->
- create_new_node(Host, ["home", H], ?MYJID)
- end, ServedHosts),
-- ets:new(gen_mod:get_module_proc(Host, pubsub_presence),
-- [set, named_table]),
- {ok, #state{host = Host, server_host = ServerHost, access = Access}}.
-
- %%--------------------------------------------------------------------
-@@ -154,6 +172,86 @@
- %% {stop, Reason, State}
- %% Description: Handling cast messages
- %%--------------------------------------------------------------------
-+handle_cast({presence, From, To, Packet}, State) ->
-+ %% When we get available presence from a subscriber, send the last
-+ %% published item.
-+ Priority = case xml:get_subtag(Packet, "priority") of
-+ false ->
-+ 0;
-+ SubEl ->
-+ case catch list_to_integer(xml:get_tag_cdata(SubEl)) of
-+ P when is_integer(P) ->
-+ P;
-+ _ ->
-+ 0
-+ end
-+ end,
-+ PType = xml:get_tag_attr_s("type", Packet),
-+ Type = case PType of
-+ "" ->
-+ if Priority < 0 ->
-+ unavailable;
-+ true ->
-+ available
-+ end;
-+ "unavailable" -> unavailable;
-+ "error" -> unavailable;
-+ _ -> none
-+ end,
-+ LJID = jlib:jid_tolower(jlib:jid_remove_resource(To)),
-+ PreviouslyAvailable =
-+ lists:member(From#jid.lresource,
-+ get_present_resources(element(1, LJID), element(2, LJID),
-+ From#jid.luser, From#jid.lserver)),
-+ Key = {element(1, LJID), element(2, LJID), From#jid.luser, From#jid.lserver},
-+ Record = #pubsub_presence{to_from = Key, resource = From#jid.lresource},
-+ Host = case LJID of
-+ {"", LServer, ""} ->
-+ LServer;
-+ _ ->
-+ LJID
-+ end,
-+ case Type of
-+ available ->
-+ mnesia:dirty_write(Record);
-+ unavailable ->
-+ mnesia:dirty_delete_object(Record);
-+ _ ->
-+ ok
-+ end,
-+ if PreviouslyAvailable == false, Type == available ->
-+ %% A new resource is available. Loop through all nodes
-+ %% and see if the contact is subscribed, and if so, and if
-+ %% the node is so configured, send the last item.
-+ Match = case Host of
-+ {_, _, _} ->
-+ #pep_node{owner_node = {LJID, '_'}, _ = '_'};
-+ _ ->
-+ #pubsub_node{host_node = {LJID, '_'}, _ = '_'}
-+ end,
-+ case catch mnesia:dirty_match_object(Match) of
-+ {'EXIT', Reason} ->
-+ ?ERROR_MSG("~p", [Reason]);
-+ Nodes ->
-+ lists:foreach(
-+ fun(N) ->
-+ Node = get_node_name(N),
-+ Info = get_node_info(N),
-+ Subscription = get_subscription(Info, From),
-+ SendWhen = get_node_option(Info, send_last_published_item),
-+ if Subscription /= none, Subscription /= pending,
-+ SendWhen == on_sub_and_presence ->
-+ send_last_published_item(jlib:jid_tolower(From), Host, Node, Info);
-+ true ->
-+ ok
-+ end
-+ end, Nodes)
-+ end,
-+ {noreply, State};
-+ true ->
-+ {noreply, State}
-+ end;
-+
- handle_cast(_Msg, State) ->
- {noreply, State}.
-
-@@ -183,7 +281,16 @@
- %% The return value is ignored.
- %%--------------------------------------------------------------------
- terminate(_Reason, State) ->
-- ejabberd_router:unregister_route(State#state.host),
-+ #state{host = Host, server_host = ServerHost} = State,
-+ mod_disco:unregister_feature(ServerHost, ?NS_PUBSUB),
-+ ejabberd_hooks:delete(disco_local_identity, ServerHost, ?MODULE, disco_local_identity, 75),
-+ ejabberd_hooks:delete(disco_sm_items, ServerHost, ?MODULE, pep_disco_items, 50),
-+ gen_iq_handler:remove_iq_handler(ejabberd_local, ServerHost, ?NS_PUBSUB),
-+ gen_iq_handler:remove_iq_handler(ejabberd_local, ServerHost, ?NS_PUBSUB_OWNER),
-+ gen_iq_handler:remove_iq_handler(ejabberd_sm, ServerHost, ?NS_PUBSUB),
-+ gen_iq_handler:remove_iq_handler(ejabberd_sm, ServerHost, ?NS_PUBSUB_OWNER),
-+ ejabberd_hooks:delete(incoming_presence_hook, ServerHost, ?MODULE, incoming_presence, 50),
-+ ejabberd_router:unregister_route(Host),
- ok.
-
- %%--------------------------------------------------------------------
-@@ -197,13 +304,13 @@
- %%% Internal functions
- %%--------------------------------------------------------------------
- do_route(Host, ServerHost, Access, From, To, Packet) ->
-- {xmlelement, Name, Attrs, Els} = Packet,
-+ {xmlelement, Name, Attrs, _Els} = Packet,
- case To of
- #jid{luser = "", lresource = ""} ->
- case Name of
- "iq" ->
- case jlib:iq_query_info(Packet) of
-- #iq{type = get, xmlns = ?NS_DISCO_INFO = XMLNS,
-+ #iq{type = get, xmlns = ?NS_DISCO_INFO,
- sub_el = SubEl} = IQ ->
- {xmlelement, _, QAttrs, _} = SubEl,
- Node = xml:get_attr_s("node", QAttrs),
-@@ -214,7 +321,7 @@
- ejabberd_router:route(To,
- From,
- jlib:iq_to_xml(Res));
-- #iq{type = get, xmlns = ?NS_DISCO_ITEMS = XMLNS,
-+ #iq{type = get, xmlns = ?NS_DISCO_ITEMS,
- sub_el = SubEl} = IQ ->
- {xmlelement, _, QAttrs, _} = SubEl,
- Node = xml:get_attr_s("node", QAttrs),
-@@ -231,7 +338,7 @@
- Packet, Error)
- end,
- ejabberd_router:route(To, From, Res);
-- #iq{type = Type, xmlns = ?NS_PUBSUB = XMLNS,
-+ #iq{type = Type, xmlns = ?NS_PUBSUB,
- sub_el = SubEl} = IQ ->
- Res =
- case iq_pubsub(Host, ServerHost, From, Type, SubEl, Access) of
-@@ -244,7 +351,7 @@
- Packet, Error)
- end,
- ejabberd_router:route(To, From, Res);
-- #iq{type = Type, xmlns = ?NS_PUBSUB_OWNER = XMLNS,
-+ #iq{type = Type, xmlns = ?NS_PUBSUB_OWNER,
- lang = Lang, sub_el = SubEl} = IQ ->
- Res =
- case iq_pubsub_owner(
-@@ -259,7 +366,7 @@
- end,
- ejabberd_router:route(To, From, Res);
- #iq{type = get, xmlns = ?NS_VCARD = XMLNS,
-- lang = Lang, sub_el = SubEl} = IQ ->
-+ lang = Lang} = IQ ->
- Res = IQ#iq{type = result,
- sub_el = [{xmlelement, "vCard",
- [{"xmlns", XMLNS}],
-@@ -276,20 +383,27 @@
- ok
- end;
- "presence" ->
-- Type = xml:get_attr_s("type", Attrs),
-- if
-- (Type == "unavailable") or (Type == "error") ->
-- ets:delete(
-- gen_mod:get_module_proc(Host, pubsub_presence),
-- {From#jid.luser, From#jid.lserver});
-- true ->
-- ets:insert(
-- gen_mod:get_module_proc(Host, pubsub_presence),
-- {{From#jid.luser, From#jid.lserver}, []})
-- end,
-+ %% XXX: subscriptions?
-+ incoming_presence(From, To, Packet),
- ok;
-- _ ->
-- ok
-+ "message" ->
-+ %% So why would anyone want to send messages to a
-+ %% pubsub service? Subscription authorization
-+ %% (section 8.6).
-+ case xml:get_attr_s("type", Attrs) of
-+ "error" ->
-+ ok;
-+ _ ->
-+ case find_authorization_response(Packet) of
-+ none ->
-+ ok;
-+ invalid ->
-+ ejabberd_router:route(To, From,
-+ jlib:make_error_reply(Packet, ?ERR_BAD_REQUEST));
-+ XFields ->
-+ handle_authorization_response(From, To, Host, Packet, XFields)
-+ end
-+ end
- end;
- _ ->
- case xml:get_attr_s("type", Attrs) of
-@@ -307,28 +421,121 @@
-
-
- node_to_string(Node) ->
-- string:strip(lists:flatten(lists:map(fun(S) -> [S, "/"] end, Node)),
-- right, $/).
-+ %% Flat (PEP) or normal node?
-+ case Node of
-+ [[_ | _] | _] ->
-+ string:strip(lists:flatten(lists:map(fun(S) -> [S, "/"] end, Node)),
-+ right, $/);
-+ [Head | _] when is_integer(Head) ->
-+ Node
-+ end.
-+
-+disco_local_identity(Acc, _From, _To, [], _Lang) ->
-+ Acc ++
-+ [{xmlelement, "identity",
-+ [{"category", "pubsub"},
-+ {"type", "pep"}], []}];
-+disco_local_identity(Acc, _From, _To, _Node, _Lang) ->
-+ Acc.
-+
-+get_table(Host) ->
-+ case Host of
-+ {_, _, _} -> pep_node;
-+ _ -> pubsub_node
-+ end.
-+
-+get_sender(Host) ->
-+ case Host of
-+ {_, _, _} ->
-+ jlib:make_jid(Host);
-+ _ ->
-+ jlib:make_jid("", Host, "")
-+ end.
-+
-+iq_pep_local(From, To,
-+ #iq{type = Type, sub_el = SubEl, xmlns = XMLNS, lang = Lang} = IQ) ->
-+ ServerHost = To#jid.lserver,
-+ %% Accept IQs to server only from our own users.
-+ if From#jid.lserver /= ServerHost ->
-+ IQ#iq{type = error, sub_el = [?ERR_FORBIDDEN, SubEl]};
-+ true ->
-+ LOwner = jlib:jid_tolower(jlib:jid_remove_resource(From)),
-+ Res = case XMLNS of
-+ ?NS_PUBSUB ->
-+ %% XXX: "access all" correct? it corresponds to access_createnode.
-+ iq_pubsub(LOwner, ServerHost, From, Type, SubEl, all);
-+ ?NS_PUBSUB_OWNER ->
-+ iq_pubsub_owner(LOwner, From, Type, Lang, SubEl)
-+ end,
-+ case Res of
-+ {result, IQRes} ->
-+ IQ#iq{type = result, sub_el = IQRes};
-+ {error, Error} ->
-+ IQ#iq{type = error, sub_el = [Error, SubEl]}
-+ end
-+ end.
-
-+iq_pep_sm(From, To,
-+ #iq{type = Type, sub_el = SubEl, xmlns = XMLNS, lang = Lang} = IQ) ->
-+ ServerHost = To#jid.lserver,
-+ LOwner = jlib:jid_tolower(jlib:jid_remove_resource(To)),
-+ Res = case XMLNS of
-+ ?NS_PUBSUB ->
-+ iq_pubsub(LOwner, ServerHost, From, Type, SubEl, all);
-+ ?NS_PUBSUB_OWNER ->
-+ iq_pubsub_owner(LOwner, From, Type, Lang, SubEl)
-+ end,
-+ case Res of
-+ {result, IQRes} ->
-+ IQ#iq{type = result, sub_el = IQRes};
-+ {error, Error} ->
-+ IQ#iq{type = error, sub_el = [Error, SubEl]}
-+ end.
-
- iq_disco_info(SNode) ->
- Node = string:tokens(SNode, "/"),
- case Node of
- [] ->
-+ PubsubFeatures =
-+ ["config-node",
-+ "create-and-configure",
-+ "create-nodes",
-+ "delete-nodes",
-+ %% "get-pending",
-+ "instant-nodes",
-+ "item-ids",
-+ %% "manage-subscriptions",
-+ %% "modify-affiliations",
-+ "outcast-affiliation",
-+ "persistent-items",
-+ "presence-notifications",
-+ "publish",
-+ "publisher-affiliation",
-+ "purge-nodes",
-+ "retract-items",
-+ "retrieve-affiliations",
-+ %% "retrieve-default",
-+ "retrieve-items",
-+ "retrieve-subscriptions",
-+ "subscribe"
-+ %% , "subscription-notifications"
-+ ],
- [{xmlelement, "identity",
- [{"category", "pubsub"},
-- {"type", "generic"},
-+ {"type", "service"},
- {"name", "ejabberd/mod_pubsub"}], []},
- {xmlelement, "feature", [{"var", ?NS_PUBSUB}], []},
-- {xmlelement, "feature", [{"var", ?NS_PUBSUB_EVENT}], []},
-- {xmlelement, "feature", [{"var", ?NS_PUBSUB_OWNER}], []},
-- {xmlelement, "feature", [{"var", ?NS_VCARD}], []}];
-+ {xmlelement, "feature", [{"var", ?NS_VCARD}], []}] ++
-+ lists:map(fun(Feature) ->
-+ {xmlelement, "feature",
-+ [{"var", ?NS_PUBSUB++"#"++Feature}], []}
-+ end, PubsubFeatures);
- _ ->
- % TODO
- []
- end.
-
--iq_disco_items(Host, From, SNode) ->
-+iq_disco_items(Host, _From, SNode) ->
- {Node,ItemID} = case SNode of
- [] ->
- {[],none};
-@@ -341,7 +548,7 @@
- end,
- {NodeList, ItemName}
- end,
-- NodeFull = string:tokens(SNode,"/"),
-+ %%NodeFull = string:tokens(SNode,"/"),
- F = fun() ->
- case mnesia:read({pubsub_node, {Host, Node}}) of
- [#pubsub_node{info = Info}] ->
-@@ -402,6 +609,32 @@
- {error, ?ERR_INTERNAL_SERVER_ERROR}
- end.
-
-+pep_disco_items(Acc, _From, To, "", _Lang) ->
-+ LJID = jlib:jid_tolower(jlib:jid_remove_resource(To)),
-+ Match = #pep_node{owner_node = {LJID, '_'}, _ = '_'},
-+ case catch mnesia:dirty_match_object(Match) of
-+ {'EXIT', Reason} ->
-+ ?ERROR_MSG("~p", [Reason]),
-+ Acc;
-+ [] ->
-+ Acc;
-+ Nodes ->
-+ Items = case Acc of
-+ {result, I} -> I;
-+ _ -> []
-+ end,
-+ NodeItems = lists:map(
-+ fun(#pep_node{owner_node = {_, Node}}) ->
-+ {xmlelement, "item",
-+ [{"jid", jlib:jid_to_string(LJID)},
-+ {"node", node_to_string(Node)}],
-+ []}
-+ end, Nodes),
-+ {result, NodeItems ++ Items}
-+ end;
-+pep_disco_items(Acc, _From, _To, _Node, _Lang) ->
-+ Acc.
-+
- iq_get_vcard(Lang) ->
- [{xmlelement, "FN", [],
- [{xmlcdata, "ejabberd/mod_pubsub"}]},
-@@ -416,14 +649,32 @@
-
-
- iq_pubsub(Host, ServerHost, From, Type, SubEl, Access) ->
-+ %% Host may be a jid tuple, in which case we use PEP.
- {xmlelement, _, _, SubEls} = SubEl,
-- case xml:remove_cdata(SubEls) of
-+ WithoutCdata = xml:remove_cdata(SubEls),
-+ Configuration = lists:filter(fun({xmlelement, Name, _, _}) ->
-+ Name == "configure"
-+ end, WithoutCdata),
-+ Action = WithoutCdata -- Configuration,
-+ case Action of
- [{xmlelement, Name, Attrs, Els}] ->
-- SNode = xml:get_attr_s("node", Attrs),
-- Node = string:tokens(SNode, "/"),
-+ %% For PEP, there is no node hierarchy.
-+ Node = case Host of
-+ {_, _, _} ->
-+ xml:get_attr_s("node", Attrs);
-+ _ ->
-+ SNode = xml:get_attr_s("node", Attrs),
-+ string:tokens(SNode, "/")
-+ end,
- case {Type, Name} of
- {set, "create"} ->
-- create_new_node(Host, Node, From, ServerHost, Access);
-+ case Configuration of
-+ [{xmlelement, "configure", _, Config}] ->
-+ create_new_node(Host, Node, From, ServerHost, Access, Config);
-+ _ ->
-+ ?INFO_MSG("Invalid configuration: ~p", [Configuration]),
-+ {error, ?ERR_BAD_REQUEST}
-+ end;
- {set, "publish"} ->
- case xml:remove_cdata(Els) of
- [{xmlelement, "item", ItemAttrs, Payload}] ->
-@@ -438,7 +689,7 @@
- ItemID = xml:get_attr_s("id", ItemAttrs),
- delete_item(Host, From, Node, ItemID);
- _ ->
-- {error, ?ERR_BAD_REQUEST}
-+ {error, extend_error(?ERR_BAD_REQUEST, "item-required")}
- end;
- {set, "subscribe"} ->
- JID = xml:get_attr_s("jid", Attrs),
-@@ -449,20 +700,15 @@
- {get, "items"} ->
- MaxItems = xml:get_attr_s("max_items", Attrs),
- get_items(Host, From, Node, MaxItems);
-- {set, "delete"} ->
-- delete_node(Host, From, Node);
-- {set, "purge"} ->
-- purge_node(Host, From, Node);
-- {get, "entities"} ->
-- get_entities(Host, From, Node);
-- {set, "entities"} ->
-- set_entities(Host, From, Node, xml:remove_cdata(Els));
- {get, "affiliations"} ->
- get_affiliations(Host, From);
-+ {get, "subscriptions"} ->
-+ get_subscriptions(Host, From);
- _ ->
- {error, ?ERR_FEATURE_NOT_IMPLEMENTED}
- end;
- _ ->
-+ ?INFO_MSG("Too many actions: ~p", [Action]),
- {error, ?ERR_BAD_REQUEST}
- end.
-
-@@ -504,16 +750,81 @@
- create_new_node(Host, Node, Owner) ->
- %% This is the case use during "bootstrapping to create the initial
- %% hierarchy. Should always be ... undefined,all
-- create_new_node(Host, Node, Owner, undefined, all).
--create_new_node(Host, Node, Owner, ServerHost, Access) ->
-- case Node of
-- [] ->
-+ create_new_node(Host, Node, Owner, undefined, all, []).
-+create_new_node(Host, Node, Owner, ServerHost, Access, Configuration) ->
-+ DefaultSet = get_table(Host), % get_table happens to DTRT here
-+ ConfigOptions = case xml:remove_cdata(Configuration) of
-+ [] ->
-+ [];
-+ [{xmlelement, "x", _Attrs, _SubEls} = XEl] ->
-+ case jlib:parse_xdata_submit(XEl) of
-+ invalid ->
-+ {error, ?ERR_BAD_REQUEST};
-+ XData ->
-+ case set_xoption(XData, [{defaults, DefaultSet}]) of
-+ NewOpts when is_list(NewOpts) ->
-+ NewOpts;
-+ Err ->
-+ Err
-+ end
-+ end;
-+ _ ->
-+ ?INFO_MSG("Configuration not understood: ~p", [Configuration]),
-+ {error, ?ERR_BAD_REQUEST}
-+ end,
-+ case {Host, Node, ConfigOptions} of
-+ {_, _, {error, _} = Error} ->
-+ Error;
-+ %% If Host is a jid tuple, we are in PEP.
-+ {{_, _, _}, [], _} ->
-+ %% And in PEP, instant nodes are not supported.
-+ {error, extend_error(?ERR_NOT_ACCEPTABLE, "nodeid-required")};
-+ {{_, _, _}, _, _} ->
-+ LOwner = Host,
-+ F = fun() ->
-+ case mnesia:read({pep_node, {LOwner, Node}}) of
-+ [_] ->
-+ {error, ?ERR_CONFLICT};
-+ [] ->
-+ Entities =
-+ ?DICT:store(
-+ LOwner,
-+ #entity{affiliation = owner,
-+ subscription = none},
-+ ?DICT:new()),
-+ mnesia:write(
-+ #pep_node{owner_node = {LOwner, Node},
-+ info = #nodeinfo{entities = Entities,
-+ options = ConfigOptions}}),
-+ ok
-+ end
-+ end,
-+ case mnesia:transaction(F) of
-+ {atomic, ok} ->
-+ {result, []};
-+ {atomic, {error, _} = Error} ->
-+ Error;
-+ _ ->
-+ {error, ?ERR_INTERNAL_SERVER_ERROR}
-+ end;
-+ {_, [], _} ->
- {LOU, LOS, _} = jlib:jid_tolower(Owner),
- HomeNode = ["home", LOS, LOU],
-- create_new_node(Host, HomeNode, Owner, ServerHost, Access),
-+ create_new_node(Host, HomeNode, Owner, ServerHost, Access, []),
- NewNode = ["home", LOS, LOU, randoms:get_string()],
-- create_new_node(Host, NewNode, Owner, ServerHost, Access);
-- _ ->
-+ %% When creating an instant node, we need to include the
-+ %% node name in the result.
-+ case create_new_node(Host, NewNode, Owner, ServerHost, Access, []) of
-+ {result, []} ->
-+ {result,
-+ [{xmlelement, "pubsub",
-+ [{"xmlns", ?NS_PUBSUB}],
-+ [{xmlelement, "create",
-+ [{"node", node_to_string(Node)}], []}]}]};
-+ {error, _} = Error ->
-+ Error
-+ end;
-+ {_, _, _} ->
- LOwner = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
- Parent = lists:sublist(Node, length(Node) - 1),
- F = fun() ->
-@@ -542,7 +853,8 @@
- #pubsub_node{host_node = {Host, Node},
- host_parent = {Host, Parent},
- info = #nodeinfo{
-- entities = Entities}}),
-+ entities = Entities,
-+ options = ConfigOptions}}),
- ok
- end
- end
-@@ -562,11 +874,7 @@
- ?XFIELD("jid-single", "Node Creator",
- "creator",
- jlib:jid_to_string(LOwner))]}]),
-- {result,
-- [{xmlelement, "pubsub",
-- [{"xmlns", ?NS_PUBSUB}],
-- [{xmlelement, "create",
-- [{"node", node_to_string(Node)}], []}]}]};
-+ {result, []};
- {atomic, {error, _} = Error} ->
- Error;
- _ ->
-@@ -579,33 +887,38 @@
-
-
- publish_item(Host, JID, Node, ItemID, Payload) ->
-+ Publisher = jlib:jid_tolower(jlib:jid_remove_resource(JID)),
-+ Table = get_table(Host),
-+ %% XXX: Host is not a host if this is PEP. Good thing that this
-+ %% hook isn't added to anywhere yet.
- ejabberd_hooks:run(pubsub_publish_item, Host,
- [JID, ?MYJID, Node, ItemID, Payload]),
-- Publisher = jlib:jid_tolower(jlib:jid_remove_resource(JID)),
- F = fun() ->
-- case mnesia:read({pubsub_node, {Host, Node}}) of
-- [#pubsub_node{info = Info} = N] ->
-+ case mnesia:read({Table, {Host, Node}}) of
-+ [N] ->
-+ Info = get_node_info(N),
- Affiliation = get_affiliation(Info, Publisher),
- Subscription = get_subscription(Info, Publisher),
- MaxSize = get_node_option(Info, max_payload_size),
- Model = get_node_option(Info, publish_model),
- Size = size(term_to_binary(Payload)),
- if
-- ((Model == open) or
-- ((Model == publishers) and
-- ((Affiliation == owner) or
-- (Affiliation == publisher))) or
-- ((Model == subscribers) and
-- (Subscription == subscribed))) and
-- (Size =< MaxSize) ->
-+ not ((Model == open) or
-+ ((Model == publishers) and
-+ ((Affiliation == owner) or
-+ (Affiliation == publisher))) or
-+ ((Model == subscribers) and
-+ (Subscription == subscribed))) ->
-+ {error, ?ERR_FORBIDDEN};
-+ (Size > MaxSize) ->
-+ {error, extend_error(?ERR_NOT_ACCEPTABLE, "payload-too-big")};
-+ true ->
- NewInfo =
- insert_item(Info, ItemID,
- Publisher, Payload),
-- mnesia:write(
-- N#pubsub_node{info = NewInfo}),
-- {result, []};
-- true ->
-- {error, ?ERR_NOT_ALLOWED}
-+ NewNode = set_node_info(N, NewInfo),
-+ mnesia:write(NewNode),
-+ {result, []}
- end;
- [] ->
- {error, ?ERR_ITEM_NOT_FOUND}
-@@ -624,20 +937,27 @@
-
- delete_item(Host, JID, Node, ItemID) ->
- Publisher = jlib:jid_tolower(jlib:jid_remove_resource(JID)),
-+ Table = get_table(Host),
- F = fun() ->
-- case mnesia:read({pubsub_node, {Host, Node}}) of
-- [#pubsub_node{info = Info} = N] ->
-- case check_item_publisher(Info, ItemID, Publisher)
-+ case mnesia:read({Table, {Host, Node}}) of
-+ [N] ->
-+ Info = get_node_info(N),
-+ ItemExists = lists:any(fun(I) ->
-+ I#item.id == ItemID
-+ end, Info#nodeinfo.items),
-+ Allowed = check_item_publisher(Info, ItemID, Publisher)
- orelse
-- (get_affiliation(Info, Publisher) == owner) of
-- true ->
-+ (get_affiliation(Info, Publisher) == owner),
-+ if not Allowed ->
-+ {error, ?ERR_FORBIDDEN};
-+ not ItemExists ->
-+ {error, ?ERR_ITEM_NOT_FOUND};
-+ true ->
- NewInfo =
- remove_item(Info, ItemID),
- mnesia:write(
-- N#pubsub_node{info = NewInfo}),
-- {result, []};
-- _ ->
-- {error, ?ERR_NOT_ALLOWED}
-+ set_node_info(N, NewInfo)),
-+ {result, []}
- end;
- [] ->
- {error, ?ERR_ITEM_NOT_FOUND}
-@@ -653,6 +973,17 @@
- {error, ?ERR_INTERNAL_SERVER_ERROR}
- end.
-
-+%% Add pubsub-specific error element
-+extend_error({xmlelement, "error", Attrs, SubEls}, Error) ->
-+ {xmlelement, "error", Attrs,
-+ [{xmlelement, Error, [{"xmlns", ?NS_PUBSUB_ERRORS}], []}
-+ | SubEls]}.
-+
-+extend_error({xmlelement, "error", Attrs, SubEls}, unsupported, Feature) ->
-+ {xmlelement, "error", Attrs,
-+ [{xmlelement, "unsupported", [{"xmlns", ?NS_PUBSUB_ERRORS},
-+ {"feature", Feature}], []}
-+ | SubEls]}.
-
- subscribe_node(Host, From, JID, Node) ->
- Sender = jlib:jid_tolower(jlib:jid_remove_resource(From)),
-@@ -665,64 +996,234 @@
- end,
- Subscriber = jlib:jid_tolower(SubscriberJID),
- SubscriberWithoutResource = jlib:jid_remove_resource(Subscriber),
-+ AuthorizedToSubscribe = Sender == SubscriberWithoutResource,
-+ Table = get_table(Host),
-+ case catch mnesia:dirty_read({Table, {Host, Node}}) of
-+ [NodeData] ->
-+ NodeInfo = get_node_info(NodeData),
-+ AllowSubscriptions = get_node_option(NodeInfo, subscribe),
-+ AccessModel = get_node_option(NodeInfo, access_model),
-+ AllowedGroups = get_node_option(NodeInfo, access_roster_groups),
-+ Affiliation = get_affiliation(NodeInfo, Subscriber),
-+ OldSubscription = get_subscription(NodeInfo, Subscriber),
-+ CurrentApprover = get_node_option(NodeInfo, current_approver);
-+ [] ->
-+ {AllowSubscriptions,
-+ AccessModel,
-+ AllowedGroups,
-+ Affiliation,
-+ OldSubscription,
-+ CurrentApprover} = {notfound, notfound, notfound, notfound, notfound, notfound};
-+ _ ->
-+ {AllowSubscriptions,
-+ AccessModel,
-+ AllowedGroups,
-+ Affiliation,
-+ OldSubscription,
-+ CurrentApprover} = {error, error, error, error, error, error}
-+ end,
-+ Subscription = if AllowSubscriptions == notfound ->
-+ {error, ?ERR_ITEM_NOT_FOUND};
-+ AllowSubscriptions == error ->
-+ {error, ?ERR_INTERNAL_SERVER_ERROR};
-+ not AuthorizedToSubscribe ->
-+ {error, extend_error(?ERR_BAD_REQUEST, "invalid-jid")};
-+ not AllowSubscriptions ->
-+ {error, extend_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "subscribe")};
-+ OldSubscription == pending ->
-+ {error, extend_error(?ERR_NOT_AUTHORIZED, "pending-subscription")};
-+ Affiliation == outcast ->
-+ {error, ?ERR_FORBIDDEN};
-+ AccessModel == open; Affiliation == owner; Affiliation == publisher ->
-+ subscribed;
-+ AccessModel == authorize ->
-+ pending;
-+ AccessModel == presence ->
-+ %% XXX: this applies only to PEP
-+ {OUser, OServer, _} = Host,
-+ {Subscription1, _Groups} =
-+ ejabberd_hooks:run_fold(
-+ roster_get_jid_info, OServer,
-+ {none, []}, [OUser, OServer, SubscriberWithoutResource]),
-+ if (Subscription1 == both) or
-+ (Subscription1 == from) ->
-+ subscribed;
-+ true ->
-+ {error, extend_error(?ERR_NOT_AUTHORIZED, "presence-subscription-required")}
-+ end;
-+ AccessModel == roster ->
-+ %% XXX: this applies only to PEP
-+ {OUser, OServer, _} = Host,
-+ {_Subscription, Groups} =
-+ ejabberd_hooks:run_fold(
-+ roster_get_jid_info, OServer,
-+ {none, []}, [OUser, OServer, SubscriberWithoutResource]),
-+ case lists:any([lists:member(Group, AllowedGroups) || Group <- Groups]) of
-+ true ->
-+ subscribed;
-+ false ->
-+ {error, extend_error(?ERR_NOT_AUTHORIZED, "not-in-roster-group")}
-+ end;
-+ AccessModel == whitelist ->
-+ %% Subscribers are added by owner (see set_entities)
-+ {error, extend_error(?ERR_NOT_ALLOWED, "closed-node")}
-+ end,
- F = fun() ->
-- case mnesia:read({pubsub_node, {Host, Node}}) of
-- [#pubsub_node{info = Info} = N] ->
-- Affiliation = get_affiliation(Info, Subscriber),
-- AllowSubscriptions = get_node_option(Info, subscribe),
-- if
-- AllowSubscriptions and
-- (Affiliation /= outcast) ->
-- NewInfo = add_subscriber(Info, Subscriber),
-- mnesia:write(N#pubsub_node{info = NewInfo}),
-- {result, [], Info};
-- true ->
-- {error, ?ERR_NOT_ALLOWED}
-- end;
-- [] ->
-- {error, ?ERR_ITEM_NOT_FOUND}
-+ case mnesia:read({Table, {Host, Node}}) of
-+ [N] ->
-+ Info = get_node_info(N),
-+ NewInfo = add_subscriber(Info, Subscriber, Subscription),
-+ mnesia:write(set_node_info(N, NewInfo)),
-+ {result, [{xmlelement, "subscription",
-+ [{"node", Node},
-+ {"jid", jlib:jid_to_string(Subscriber)},
-+ {"subscription",
-+ subscription_to_string(Subscription)}],
-+ []}],
-+ Info}
- end
- end,
-- if
-- Sender == SubscriberWithoutResource ->
-+ case Subscription of
-+ {error, _} = Error ->
-+ Error;
-+ _ ->
- case mnesia:transaction(F) of
- {atomic, {error, _} = Error} ->
- Error;
- {atomic, {result, Res, Info}} ->
-- case get_node_option(Info, send_item_subscribe) of
-- true ->
-- ItemsEls =
-- lists:map(
-- fun(#item{id = ItemID,
-- payload = Payload}) ->
-- ItemAttrs = case ItemID of
-- "" -> [];
-- _ -> [{"id", ItemID}]
-- end,
-- {xmlelement, "item",
-- ItemAttrs, Payload}
-- end, Info#nodeinfo.items),
-- Stanza =
-- {xmlelement, "message",
-- [],
-- [{xmlelement, "x",
-- [{"xmlns", ?NS_PUBSUB_EVENT}],
-- [{xmlelement, "items",
-- [{"node", node_to_string(Node)}],
-- ItemsEls}]}]},
-- ejabberd_router:route(
-- ?MYJID, jlib:make_jid(Subscriber), Stanza);
-- false ->
-- ok
-- end,
-+ if Subscription == subscribed ->
-+ SendLastPublishedItem = get_node_option(Info, send_last_published_item),
-+ if SendLastPublishedItem /= never ->
-+ send_last_published_item(Subscriber, Host, Node, Info);
-+ true ->
-+ ok
-+ end;
-+ Subscription == pending ->
-+ %% send authorization request to node owner (section 8.6)
-+
-+ %% XXX: fix translation
-+ Lang = "en",
-+ send_authorization_request(Lang, CurrentApprover, Subscriber, Node, Host)
-+ end,
- {result, Res};
- _ ->
- {error, ?ERR_INTERNAL_SERVER_ERROR}
-- end;
-- true ->
-- {error, ?ERR_NOT_ALLOWED}
-+ end
-+ end.
-+
-+send_authorization_request(Lang, Approver, Subscriber, Node, Host) ->
-+ Stanza =
-+ {xmlelement, "message",
-+ [],
-+ [{xmlelement, "x", [{"xmlns", ?NS_XDATA},
-+ {"type", "form"}],
-+ [{xmlelement, "title", [],
-+ [{xmlcdata, translate:translate(Lang, "PubSub subscriber request")}]},
-+ {xmlelement, "instructions", [],
-+ [{xmlcdata, translate:translate(Lang, "Choose whether to approve this entity's subscription.")}]},
-+ {xmlelement, "field", [{"var", "FORM_TYPE"}, {"type", "hidden"}],
-+ [{xmlelement, "value", [], [{xmlcdata, ?NS_PUBSUB_SUB_AUTH}]}]},
-+ {xmlelement, "field", [{"var", "pubsub#node"}, {"type", "text-single"},
-+ {"label", translate:translate(Lang, "Node ID")}],
-+ [{xmlelement, "value", [], [{xmlcdata, node_to_string(Node)}]}]},
-+ {xmlelement, "field", [{"var", "pubsub#subscriber_jid"},
-+ {"type", "jid-single"},
-+ {"label", translate:translate(Lang, "Subscriber Address")}],
-+ [{xmlelement, "value", [], [{xmlcdata, jlib:jid_to_string(Subscriber)}]}]},
-+ {xmlelement, "field", [{"var", "pubsub#allow"}, {"type", "boolean"},
-+ {"label", translate:translate(Lang, "Allow this JID to subscribe to this pubsub node?")}],
-+ [{xmlelement, "value", [], [{xmlcdata, "false"}]}]}]}]},
-+ ejabberd_router:route(get_sender(Host), Approver, Stanza).
-+
-+find_authorization_response(Packet) ->
-+ {xmlelement, _Name, _Attrs, Els} = Packet,
-+ XData1 = lists:map(fun({xmlelement, "x", XAttrs, _} = XEl) ->
-+ case xml:get_attr_s("xmlns", XAttrs) of
-+ ?NS_XDATA ->
-+ case xml:get_attr_s("type", XAttrs) of
-+ "cancel" ->
-+ none;
-+ _ ->
-+ jlib:parse_xdata_submit(XEl)
-+ end;
-+ _ ->
-+ none
-+ end;
-+ (_) ->
-+ none
-+ end, xml:remove_cdata(Els)),
-+ XData = lists:filter(fun(E) -> E /= none end, XData1),
-+ case XData of
-+ [invalid] -> invalid;
-+ [] -> none;
-+ [XFields] when is_list(XFields) ->
-+ case lists:keysearch("FORM_TYPE", 1, XFields) of
-+ {value, {_, ?NS_PUBSUB_SUB_AUTH}} ->
-+ XFields;
-+ _ ->
-+ invalid
-+ end
- end.
-
-+handle_authorization_response(From, To, Host, Packet, XFields) ->
-+ case {lists:keysearch("pubsub#node", 1, XFields),
-+ lists:keysearch("pubsub#subscriber_jid", 1, XFields),
-+ lists:keysearch("pubsub#allow", 1, XFields)} of
-+ {{value, {_, SNode}}, {value, {_, SSubscriber}},
-+ {value, {_, SAllow}}} ->
-+ Node = case Host of
-+ {_, _, _} ->
-+ SNode;
-+ _ ->
-+ string:tokens(SNode, "/")
-+ end,
-+ Subscriber = jlib:string_to_jid(SSubscriber),
-+ Allow = case SAllow of
-+ "1" -> true;
-+ "true" -> true;
-+ _ -> false
-+ end,
-+ Table = get_table(Host),
-+ F = fun() ->
-+ case mnesia:read({Table, {Host, Node}}) of
-+ [N] ->
-+ Info = get_node_info(N),
-+ Subscription = get_subscription(Info, Subscriber),
-+ Approver = get_node_option(N, current_approver),
-+ IsApprover = jlib:jid_tolower(jlib:jid_remove_resource(From)) ==
-+ jlib:jid_tolower(jlib:jid_remove_resource(Approver)),
-+ if not IsApprover ->
-+ {error, ?ERR_FORBIDDEN};
-+ Subscription /= pending ->
-+ {error, ?ERR_UNEXPECTED_REQUEST};
-+ true ->
-+ NewSubscription = case Allow of
-+ true -> subscribed;
-+ false -> none
-+ end,
-+ NewInfo = add_subscriber(Info, Subscriber, NewSubscription),
-+ mnesia:write(set_node_info(N, NewInfo)),
-+ NewSubscription
-+ end;
-+ [] ->
-+ {error, ?ERR_ITEM_NOT_FOUND}
-+ end
-+ end,
-+ case mnesia:transaction(F) of
-+ {atomic, {error, Error}} ->
-+ ejabberd_router:route(To, From,
-+ jlib:make_error_reply(Packet, Error));
-+ {atomic, NewSubscription} ->
-+ %% XXX: notify about subscription state change, section 12.11
-+ ok;
-+ _ ->
-+ ejabberd_router:route(To, From,
-+ jlib:make_error_reply(Packet, ?ERR_INTERNAL_SERVER_ERROR))
-+ end;
-+ _ ->
-+ ejabberd_router:route(To, From,
-+ jlib:make_error_reply(Packet, ?ERR_NOT_ACCEPTABLE))
-+ end.
-
- unsubscribe_node(Host, From, JID, Node) ->
- Sender = jlib:jid_tolower(jlib:jid_remove_resource(From)),
-@@ -734,19 +1235,21 @@
- J
- end,
- Subscriber = jlib:jid_tolower(SubscriberJID),
-+ Table = get_table(Host),
- F = fun() ->
-- case mnesia:read({pubsub_node, {Host, Node}}) of
-- [#pubsub_node{info = Info} = N] ->
-+ case mnesia:read({Table, {Host, Node}}) of
-+ [N] ->
-+ Info = get_node_info(N),
- Subscription = get_subscription(Info, Subscriber),
- if
- Subscription /= none ->
- NewInfo =
- remove_subscriber(Info, Subscriber),
- mnesia:write(
-- N#pubsub_node{info = NewInfo}),
-+ set_node_info(N, NewInfo)),
- {result, []};
- true ->
-- {error, ?ERR_NOT_ALLOWED}
-+ {error, extend_error(?ERR_UNEXPECTED_REQUEST, "not-subscribed")}
- end;
- [] ->
- {error, ?ERR_ITEM_NOT_FOUND}
-@@ -763,7 +1266,7 @@
- {error, ?ERR_INTERNAL_SERVER_ERROR}
- end;
- true ->
-- {error, ?ERR_NOT_ALLOWED}
-+ {error, ?ERR_FORBIDDEN}
- end.
-
-
-@@ -780,12 +1283,14 @@
- Val
- end
- end,
-+ Table = get_table(Host),
- case MaxItems of
- {error, _} = Error ->
- Error;
- _ ->
-- case catch mnesia:dirty_read(pubsub_node, {Host, Node}) of
-- [#pubsub_node{info = Info}] ->
-+ case catch mnesia:dirty_read(Table, {Host, Node}) of
-+ [N] ->
-+ Info = get_node_info(N),
- Items = lists:sublist(Info#nodeinfo.items, MaxItems),
- ItemsEls =
- lists:map(
-@@ -810,30 +1315,39 @@
-
- delete_node(Host, JID, Node) ->
- Owner = jlib:jid_tolower(jlib:jid_remove_resource(JID)),
-+ Table = get_table(Host),
- F = fun() ->
-- case mnesia:read({pubsub_node, {Host, Node}}) of
-- [#pubsub_node{info = Info}] ->
-+ case mnesia:read({Table, {Host, Node}}) of
-+ [N1] ->
-+ Info = get_node_info(N1),
- case get_affiliation(Info, Owner) of
- owner ->
-- % TODO: don't iterate over entire table
-- Removed =
-- mnesia:foldl(
-- fun(#pubsub_node{host_node = {_, N},
-- info = NInfo}, Acc) ->
-- case lists:prefix(Node, N) of
-- true ->
-- [{N, NInfo} | Acc];
-- _ ->
-- Acc
-- end
-- end, [], pubsub_node),
-- lists:foreach(
-- fun({N, _}) ->
-- mnesia:delete({pubsub_node, {Host, N}})
-- end, Removed),
-- {removed, Removed};
-+ %% PEP nodes are not hierarchical, so removal is easier.
-+ case Table of
-+ pep_node ->
-+ mnesia:delete({Table, {Host, Node}}),
-+ {removed, [{N1, Info}]};
-+ pubsub_node ->
-+ %% TODO: don't iterate over entire table
-+ Removed =
-+ mnesia:foldl(
-+ fun(#pubsub_node{host_node = {_, N},
-+ info = NInfo}, Acc) ->
-+ case lists:prefix(Node, N) of
-+ true ->
-+ [{N, NInfo} | Acc];
-+ _ ->
-+ Acc
-+ end
-+ end, [], pubsub_node),
-+ lists:foreach(
-+ fun({N, _}) ->
-+ mnesia:delete({pubsub_node, {Host, N}})
-+ end, Removed),
-+ {removed, Removed}
-+ end;
- _ ->
-- {error, ?ERR_NOT_ALLOWED}
-+ {error, ?ERR_FORBIDDEN}
- end;
- [] ->
- {error, ?ERR_ITEM_NOT_FOUND}
-@@ -844,7 +1358,6 @@
- Error;
- {atomic, {removed, Removed}} ->
- broadcast_removed_node(Host, Removed),
-- Lang = "",
- broadcast_retract_item(
- Host, ["pubsub", "nodes"], node_to_string(Node)),
- {result, []};
-@@ -855,17 +1368,18 @@
-
- purge_node(Host, JID, Node) ->
- Owner = jlib:jid_tolower(jlib:jid_remove_resource(JID)),
-+ Table = get_table(Host),
- F = fun() ->
-- case mnesia:read({pubsub_node, {Host, Node}}) of
-- [#pubsub_node{info = Info} = N] ->
-+ case mnesia:read({Table, {Host, Node}}) of
-+ [N] ->
-+ Info = get_node_info(N),
- case get_affiliation(Info, Owner) of
- owner ->
- NewInfo = Info#nodeinfo{items = []},
-- mnesia:write(
-- N#pubsub_node{info = NewInfo}),
-- {result, Info#nodeinfo.items, []};
-+ mnesia:write(set_node_info(N, NewInfo)),
-+ {result, []};
- _ ->
-- {error, ?ERR_NOT_ALLOWED}
-+ {error, ?ERR_FORBIDDEN}
- end;
- [] ->
- {error, ?ERR_ITEM_NOT_FOUND}
-@@ -874,52 +1388,170 @@
- case mnesia:transaction(F) of
- {atomic, {error, _} = Error} ->
- Error;
-- {atomic, {result, Items, Res}} ->
-- lists:foreach(
-- fun(#item{id = ItemID}) ->
-- broadcast_retract_item(Host, Node, ItemID)
-- end, Items),
-+ {atomic, {result, Res}} ->
-+ broadcast_purge_node(Host, Node),
- {result, Res};
- _ ->
- {error, ?ERR_INTERNAL_SERVER_ERROR}
- end.
-
-
--get_entities(Host, OJID, Node) ->
-+owner_get_subscriptions(Host, OJID, Node) ->
- Owner = jlib:jid_tolower(jlib:jid_remove_resource(OJID)),
-- case catch mnesia:dirty_read(pubsub_node, {Host, Node}) of
-- [#pubsub_node{info = Info}] ->
-+ Table = get_table(Host),
-+ case catch mnesia:dirty_read(Table, {Host, Node}) of
-+ [N] ->
-+ Info = get_node_info(N),
- case get_affiliation(Info, Owner) of
- owner ->
- Entities = Info#nodeinfo.entities,
- EntitiesEls =
- ?DICT:fold(
- fun(JID,
-- #entity{affiliation = Affiliation,
-- subscription = Subscription},
-+ #entity{subscription = Subscription},
- Acc) ->
-- [{xmlelement, "entity",
-- [{"jid", jlib:jid_to_string(JID)},
-- {"affiliation",
-- affiliation_to_string(Affiliation)},
-- {"subscription",
-- subscription_to_string(Subscription)}],
-- []} | Acc]
-+ case Subscription of
-+ none ->
-+ Acc;
-+ _ ->
-+ [{xmlelement, "subscription",
-+ [{"jid", jlib:jid_to_string(JID)},
-+ {"subscription",
-+ subscription_to_string(Subscription)}],
-+ []} | Acc]
-+ end
- end, [], Entities),
- {result, [{xmlelement, "pubsub",
-- [{"xmlns", ?NS_PUBSUB_EVENT}],
-- [{xmlelement, "entities",
-+ [{"xmlns", ?NS_PUBSUB_OWNER}],
-+ [{xmlelement, "subscriptions",
- [{"node", node_to_string(Node)}],
- EntitiesEls}]}]};
- _ ->
-- {error, ?ERR_NOT_ALLOWED}
-+ {error, ?ERR_FORBIDDEN}
- end;
- _ ->
- {error, ?ERR_ITEM_NOT_FOUND}
- end.
-
-
--set_entities(Host, OJID, Node, EntitiesEls) ->
-+owner_set_subscriptions(Host, OJID, Node, EntitiesEls) ->
-+ %% XXX: not updated for PEP and new pubsub revision
-+ Owner = jlib:jid_tolower(jlib:jid_remove_resource(OJID)),
-+ Entities =
-+ lists:foldl(
-+ fun(El, Acc) ->
-+ case Acc of
-+ error ->
-+ error;
-+ _ ->
-+ case El of
-+ {xmlelement, "entity", Attrs, _} ->
-+ JID = jlib:string_to_jid(
-+ xml:get_attr_s("jid", Attrs)),
-+ Affiliation =
-+ case xml:get_attr_s("affiliation",
-+ Attrs) of
-+ "owner" -> owner;
-+ "publisher" -> publisher;
-+ "outcast" -> outcast;
-+ "none" -> none;
-+ _ -> false
-+ end,
-+ Subscription =
-+ case xml:get_attr_s("subscription",
-+ Attrs) of
-+ "subscribed" -> subscribed;
-+ "pending" -> pending;
-+ "unconfigured" -> unconfigured;
-+ "none" -> none;
-+ _ -> false
-+ end,
-+ if
-+ (JID == error) or
-+ (Affiliation == false) or
-+ (Subscription == false) ->
-+ error;
-+ true ->
-+ [{jlib:jid_tolower(JID),
-+ #entity{
-+ affiliation = Affiliation,
-+ subscription = Subscription}} |
-+ Acc]
-+ end
-+ end
-+ end
-+ end, [], EntitiesEls),
-+ case Entities of
-+ error ->
-+ {error, ?ERR_BAD_REQUEST};
-+ _ ->
-+ F = fun() ->
-+ case mnesia:read({pubsub_node, {Host, Node}}) of
-+ [#pubsub_node{info = Info} = N] ->
-+ case get_affiliation(Info, Owner) of
-+ owner ->
-+ NewInfo =
-+ set_info_entities(Info, Entities),
-+ mnesia:write(
-+ N#pubsub_node{info = NewInfo}),
-+ {result, []};
-+ _ ->
-+ {error, ?ERR_NOT_ALLOWED}
-+ end;
-+ [] ->
-+ {error, ?ERR_ITEM_NOT_FOUND}
-+ end
-+ end,
-+ case mnesia:transaction(F) of
-+ {atomic, {error, _} = Error} ->
-+ Error;
-+ {atomic, {result, _}} ->
-+ {result, []};
-+ _ ->
-+ {error, ?ERR_INTERNAL_SERVER_ERROR}
-+ end
-+ end.
-+
-+owner_get_affiliations(Host, OJID, Node) ->
-+ Owner = jlib:jid_tolower(jlib:jid_remove_resource(OJID)),
-+ Table = get_table(Host),
-+ case catch mnesia:dirty_read(Table, {Host, Node}) of
-+ [N] ->
-+ Info = get_node_info(N),
-+ case get_affiliation(Info, Owner) of
-+ owner ->
-+ Entities = Info#nodeinfo.entities,
-+ EntitiesEls =
-+ ?DICT:fold(
-+ fun(JID,
-+ #entity{affiliation = Affiliation},
-+ Acc) ->
-+ case Affiliation of
-+ none ->
-+ Acc;
-+ _ ->
-+ [{xmlelement, "affiliation",
-+ [{"jid", jlib:jid_to_string(JID)},
-+ {"affiliation",
-+ affiliation_to_string(Affiliation)}],
-+ []} | Acc]
-+ end
-+ end, [], Entities),
-+ {result, [{xmlelement, "pubsub",
-+ [{"xmlns", ?NS_PUBSUB_OWNER}],
-+ [{xmlelement, "affiliations",
-+ [{"node", node_to_string(Node)}],
-+ EntitiesEls}]}]};
-+ _ ->
-+ {error, ?ERR_FORBIDDEN}
-+ end;
-+ _ ->
-+ {error, ?ERR_ITEM_NOT_FOUND}
-+ end.
-+
-+
-+owner_set_affiliations(Host, OJID, Node, EntitiesEls) ->
-+ %% XXX: not updated for PEP and new pubsub revision
- Owner = jlib:jid_tolower(jlib:jid_remove_resource(OJID)),
- Entities =
- lists:foldl(
-@@ -999,42 +1631,114 @@
-
- get_affiliations(Host, JID) ->
- LJID = jlib:jid_tolower(jlib:jid_remove_resource(JID)),
-+ Table = get_table(Host),
-+ Template = case Table of
-+ pubsub_node ->
-+ #pubsub_node{_ = '_'};
-+ pep_node ->
-+ #pep_node{_ = '_'}
-+ end,
- case catch mnesia:dirty_select(
-- pubsub_node,
-- [{#pubsub_node{_ = '_'},
-+ Table,
-+ [{Template,
- [],
- ['$_']}]) of
- {'EXIT', _} ->
-- {error, ?ERR_INTERNAL_SERVER_ERROR};
-+ {error, ?ERR_INTERNAL_SERVER_ERROR};
- Nodes ->
-- Entities =
-- lists:flatmap(
-- fun(#pubsub_node{host_node = {H, Node}, info = Info})
-- when H == Host ->
-- Affiliation = get_affiliation(Info, LJID),
-- Subscription = get_subscription(Info, LJID),
-- if
-- (Affiliation /= none) or
-- (Subscription /= none) ->
-- [{xmlelement, "entity",
-- [{"node", node_to_string(Node)},
-- {"jid", jlib:jid_to_string(JID)},
-- {"affiliation",
-- affiliation_to_string(Affiliation)},
-- {"subscription",
-- subscription_to_string(Subscription)}],
-- []}];
-- true ->
-- []
-- end;
-- (_) ->
-- []
-- end, Nodes),
-- {result, [{xmlelement, "pubsub",
-- [{"xmlns", ?NS_PUBSUB_EVENT}],
-- [{xmlelement, "affiliations", [],
-- Entities}]}]}
-- end.
-+ Entities =
-+ lists:flatmap(
-+ fun(N) ->
-+ Info = get_node_info(N),
-+ {H, Node} =
-+ case Table of
-+ pubsub_node ->
-+ N#pubsub_node.host_node;
-+ pep_node ->
-+ N#pep_node.owner_node
-+ end,
-+ if Host == H ->
-+ Affiliation = get_affiliation(Info, LJID),
-+ if Affiliation /= none ->
-+ [{xmlelement, "affiliation",
-+ [{"node", node_to_string(Node)},
-+ {"affiliation",
-+ affiliation_to_string(Affiliation)}],
-+ []}];
-+ true ->
-+ []
-+ end;
-+ true ->
-+ []
-+ end
-+ end,
-+ Nodes),
-+ case Entities of
-+ [] ->
-+ {error, ?ERR_ITEM_NOT_FOUND};
-+ _ ->
-+ {result, [{xmlelement, "pubsub",
-+ [{"xmlns", ?NS_PUBSUB}],
-+ [{xmlelement, "affiliations", [],
-+ Entities}]}]}
-+ end
-+ end.
-+
-+get_subscriptions(Host, JID) ->
-+ LJID = jlib:jid_tolower(jlib:jid_remove_resource(JID)),
-+ Table = get_table(Host),
-+ Template = case Table of
-+ pubsub_node ->
-+ #pubsub_node{_ = '_'};
-+ pep_node ->
-+ #pep_node{_ = '_'}
-+ end,
-+ case catch mnesia:dirty_select(
-+ Table,
-+ [{Template,
-+ [],
-+ ['$_']}]) of
-+ {'EXIT', _} ->
-+ {error, ?ERR_INTERNAL_SERVER_ERROR};
-+ Nodes ->
-+ Entities =
-+ lists:flatmap(
-+ fun(N) ->
-+ Info = get_node_info(N),
-+ {H, Node} =
-+ case Table of
-+ pubsub_node ->
-+ N#pubsub_node.host_node;
-+ pep_node ->
-+ N#pep_node.owner_node
-+ end,
-+ if Host == H ->
-+ Subscription = get_subscription(Info, LJID),
-+ if Subscription /= none ->
-+ [{xmlelement, "subscription",
-+ [{"node", node_to_string(Node)},
-+ {"jid", jlib:jid_to_string(LJID)}, %XXX: full JID?
-+ {"subscription",
-+ subscription_to_string(Subscription)}],
-+ []}];
-+ true ->
-+ []
-+ end;
-+ true ->
-+ []
-+ end
-+ end,
-+ Nodes),
-+ case Entities of
-+ [] ->
-+ {error, ?ERR_ITEM_NOT_FOUND};
-+ _ ->
-+ {result, [{xmlelement, "pubsub",
-+ [{"xmlns", ?NS_PUBSUB}],
-+ [{xmlelement, "subscriptions", [],
-+ Entities}]}]}
-+ end
-+ end.
-
-
-
-@@ -1123,18 +1827,18 @@
- false
- end.
-
--add_subscriber(Info, Subscriber) ->
-+add_subscriber(Info, Subscriber, Subscription) ->
- Entities = Info#nodeinfo.entities,
- case ?DICT:find(Subscriber, Entities) of
- {ok, Entity} ->
- Info#nodeinfo{
- entities = ?DICT:store(Subscriber,
-- Entity#entity{subscription = subscribed},
-+ Entity#entity{subscription = Subscription},
- Entities)};
- _ ->
- Info#nodeinfo{
- entities = ?DICT:store(Subscriber,
-- #entity{subscription = subscribed},
-+ #entity{subscription = Subscription},
- Entities)}
- end.
-
-@@ -1167,32 +1871,48 @@
- end, Info#nodeinfo.entities, Entities),
- Info#nodeinfo{entities = NewEntities}.
-
-+send_last_published_item(Subscriber, Host, Node, Info) ->
-+ case Info#nodeinfo.items of
-+ [] ->
-+ %% No published items - can't send anything.
-+ ok;
-+ [#item{id = ItemID, payload = Payload} | _] ->
-+ %% At least one item - send the last one.
-+ ItemAttrs = case ItemID of
-+ "" -> [];
-+ _ -> [{"id", ItemID}]
-+ end,
-+ ItemsEl = {xmlelement, "item",
-+ ItemAttrs, Payload},
-+ Stanza =
-+ {xmlelement, "message",
-+ [],
-+ [{xmlelement, "event",
-+ [{"xmlns", ?NS_PUBSUB_EVENT}],
-+ [{xmlelement, "items",
-+ [{"node", node_to_string(Node)}],
-+ [ItemsEl]}]}]},
-+ ejabberd_router:route(
-+ get_sender(Host), jlib:make_jid(Subscriber), Stanza)
-+ end.
-+
-
-
- broadcast_publish_item(Host, Node, ItemID, Payload) ->
-- case catch mnesia:dirty_read(pubsub_node, {Host, Node}) of
-- [#pubsub_node{info = Info}] ->
-+ ?DEBUG("broadcasting for ~p / ~p", [Host, Node]),
-+ Table = get_table(Host),
-+ Sender = get_sender(Host),
-+ case catch mnesia:dirty_read(Table, {Host, Node}) of
-+ [N] ->
-+ Info = get_node_info(N),
- ?DICT:fold(
- fun(JID, #entity{subscription = Subscription}, _) ->
-- Present = case get_node_option(
-- Info, presence_based_delivery) of
-- true ->
-- case ets:lookup(
-- gen_mod:get_module_proc(Host, pubsub_presence),
-- {element(1, JID),
-- element(2, JID)}) of
-- [_] ->
-- true;
-- [] ->
-- false
-- end;
-- false ->
-- true
-- end,
-+ Resources = get_recipient_resources(Host, JID, Info),
-+ ?DEBUG("subscriber ~p: delivering to resources ~p", [JID, Resources]),
- if
-- (Subscription /= none) and
-- (Subscription /= pending) and
-- Present ->
-+ Subscription /= none,
-+ Subscription /= pending,
-+ Resources /= [] ->
- ItemAttrs = case ItemID of
- "" -> [];
- _ -> [{"id", ItemID}]
-@@ -1213,8 +1933,12 @@
- [{xmlelement, "item",
- ItemAttrs,
- Content}]}]}]},
-- ejabberd_router:route(
-- ?MYJID, jlib:make_jid(JID), Stanza);
-+ TheJID = jlib:make_jid(JID),
-+ lists:foreach(fun(Resource) ->
-+ FullJID = jlib:jid_replace_resource(TheJID, Resource),
-+ ejabberd_router:route(
-+ Sender, FullJID, Stanza)
-+ end, Resources);
- true ->
- ok
- end
-@@ -1225,10 +1949,14 @@
-
-
- broadcast_retract_item(Host, Node, ItemID) ->
-- case catch mnesia:dirty_read(pubsub_node, {Host, Node}) of
-- [#pubsub_node{info = Info}] ->
-+ Table = get_table(Host),
-+ Sender = get_sender(Host),
-+ case catch mnesia:dirty_read(Table, {Host, Node}) of
-+ [N] ->
-+ Info = get_node_info(N),
- case get_node_option(Info, notify_retract) of
- true ->
-+ %% XXX: presence-based notifications?
- ?DICT:fold(
- fun(JID, #entity{subscription = Subscription}, _) ->
- if
-@@ -1240,14 +1968,48 @@
- end,
- Stanza =
- {xmlelement, "message", [],
-- [{xmlelement, "x",
-+ [{xmlelement, "event",
- [{"xmlns", ?NS_PUBSUB_EVENT}],
- [{xmlelement, "items",
- [{"node", node_to_string(Node)}],
- [{xmlelement, "retract",
- ItemAttrs, []}]}]}]},
- ejabberd_router:route(
-- ?MYJID, jlib:make_jid(JID), Stanza);
-+ Sender, jlib:make_jid(JID), Stanza);
-+ true ->
-+ ok
-+ end
-+ end, ok, Info#nodeinfo.entities);
-+ false ->
-+ ok
-+ end;
-+ _ ->
-+ false
-+ end.
-+
-+broadcast_purge_node(Host, Node) ->
-+ Table = get_table(Host),
-+ Sender = get_sender(Host),
-+ case catch mnesia:dirty_read(Table, {Host, Node}) of
-+ [N] ->
-+ Info = get_node_info(N),
-+ case get_node_option(Info, notify_retract) of
-+ true ->
-+ %% XXX: presence-based notifications?
-+ ?DICT:fold(
-+ fun(JID, #entity{subscription = Subscription}, _) ->
-+ if
-+ (Subscription /= none) and
-+ (Subscription /= pending) ->
-+ Stanza =
-+ {xmlelement, "message", [],
-+ [{xmlelement, "event",
-+ [{"xmlns", ?NS_PUBSUB_EVENT}],
-+ [{xmlelement, "purge",
-+ [{"node", node_to_string(Node)}],
-+ []}]}]},
-+ ejabberd_router:route(
-+ Sender, jlib:make_jid(JID), Stanza);
- true ->
- ok
- end
-@@ -1265,6 +2027,7 @@
- fun({Node, Info}) ->
- case get_node_option(Info, notify_delete) of
- true ->
-+ %% XXX: presence-based notifications?
- Entities = Info#nodeinfo.entities,
- ?DICT:fold(
- fun(JID, #entity{subscription = Subscription}, _) ->
-@@ -1273,13 +2036,13 @@
- (Subscription /= pending) ->
- Stanza =
- {xmlelement, "message", [],
-- [{xmlelement, "x",
-+ [{xmlelement, "event",
- [{"xmlns", ?NS_PUBSUB_EVENT}],
- [{xmlelement, "delete",
- [{"node", node_to_string(Node)}],
- []}]}]},
- ejabberd_router:route(
-- ?MYJID, jlib:make_jid(JID), Stanza);
-+ get_sender(Host), jlib:make_jid(JID), Stanza);
- true ->
- ok
- end
-@@ -1291,31 +2054,19 @@
-
-
- broadcast_config_notification(Host, Node, Lang) ->
-- case catch mnesia:dirty_read(pubsub_node, {Host, Node}) of
-- [#pubsub_node{info = Info}] ->
-+ Table = get_table(Host),
-+ case catch mnesia:dirty_read(Table, {Host, Node}) of
-+ [N] ->
-+ Info = get_node_info(N),
- case get_node_option(Info, notify_config) of
- true ->
- ?DICT:fold(
- fun(JID, #entity{subscription = Subscription}, _) ->
-- Present = case get_node_option(
-- Info, presence_based_delivery) of
-- true ->
-- case ets:lookup(
-- gen_mod:get_module_proc(Host, pubsub_presence),
-- {element(1, JID),
-- element(2, JID)}) of
-- [_] ->
-- true;
-- [] ->
-- false
-- end;
-- false ->
-- true
-- end,
-+ Resources = get_recipient_resources(Host, JID, Info),
- if
-- (Subscription /= none) and
-- (Subscription /= pending) and
-- Present ->
-+ Subscription /= none,
-+ Subscription /= pending,
-+ Resources /= [] ->
- Fields = get_node_config_xfields(
- Node, Info, Lang),
- Content = case get_node_option(
-@@ -1323,22 +2074,24 @@
- true ->
- [{xmlelement, "x",
- [{"xmlns", ?NS_XDATA},
-- {"type", "form"}],
-+ {"type", "result"}],
- Fields}];
- false ->
- []
- end,
- Stanza =
- {xmlelement, "message", [],
-- [{xmlelement, "x",
-+ [{xmlelement, "event",
- [{"xmlns", ?NS_PUBSUB_EVENT}],
-- [{xmlelement, "items",
-+ [{xmlelement, "configuration",
- [{"node", node_to_string(Node)}],
-- [{xmlelement, "item",
-- [{"id", "configuration"}],
-- Content}]}]}]},
-- ejabberd_router:route(
-- ?MYJID, jlib:make_jid(JID), Stanza);
-+ Content}]}]},
-+ TheJID = jlib:make_jid(JID),
-+ lists:foreach(fun(Resource) ->
-+ FullJID = jlib:jid_replace_resource(TheJID, Resource),
-+ ejabberd_router:route(
-+ get_sender(Host), FullJID, Stanza)
-+ end, Resources);
- true ->
- ok
- end
-@@ -1350,19 +2103,74 @@
- false
- end.
-
-+get_recipient_resources(Host, JID, Info) ->
-+ %% Return a list of resources that are supposed to receive event
-+ %% notifications. An empty string in that list means a bare JID.
-+ case get_node_option(Info, presence_based_delivery) of
-+ false ->
-+ [""];
-+ true ->
-+ To = case Host of
-+ {_, _, _} ->
-+ Host;
-+ _ ->
-+ {"", Host, ""}
-+ end,
-+ Resources = get_present_resources(To, JID),
-+ %% Here, there is a difference between JEP-0060 and
-+ %% JEP-0163. JEP-0060, section 12.1, says that the
-+ %% service should not attempt to guess the correct
-+ %% resource. JEP-0163, section 7.1.1.2, says that the
-+ %% service must send a notification to each resource.
-+ case Info#nodeinfo.options of
-+ [{default, pep_node} | _] ->
-+ Resources;
-+ _ ->
-+ %% That means, if noone is online, nothing is
-+ %% sent. If someone is online, send one
-+ %% notification.
-+ case Resources of
-+ [] ->
-+ [];
-+ _ ->
-+ [""]
-+ end
-+ end
-+ end.
-+
-
-
- iq_pubsub_owner(Host, From, Type, Lang, SubEl) ->
- {xmlelement, _, _, SubEls} = SubEl,
- case xml:remove_cdata(SubEls) of
- [{xmlelement, Name, Attrs, Els}] ->
-- SNode = xml:get_attr_s("node", Attrs),
-- Node = string:tokens(SNode, "/"),
-+ %% For PEP, there is no node hierarchy.
-+ Node = case Host of
-+ {_, _, _} ->
-+ xml:get_attr_s("node", Attrs);
-+ _ ->
-+ SNode = xml:get_attr_s("node", Attrs),
-+ string:tokens(SNode, "/")
-+ end,
- case {Type, Name} of
- {get, "configure"} ->
- get_node_config(Host, From, Node, Lang);
- {set, "configure"} ->
- set_node_config(Host, From, Node, Els, Lang);
-+ {get, "default"} ->
-+ {error, extend_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "retrieve-default")};
-+ {set, "delete"} ->
-+ delete_node(Host, From, Node);
-+ {set, "purge"} ->
-+ purge_node(Host, From, Node);
-+ {get, "subscriptions"} ->
-+ owner_get_subscriptions(Host, From, Node);
-+ {set, "subscriptions"} ->
-+ owner_set_subscriptions(Host, From, Node, xml:remove_cdata(Els));
-+ {get, "affiliations"} ->
-+ owner_get_affiliations(Host, From, Node);
-+ {set, "affiliations"} ->
-+ owner_set_affiliations(Host, From, Node, xml:remove_cdata(Els));
- _ ->
- {error, ?ERR_FEATURE_NOT_IMPLEMENTED}
- end;
-@@ -1371,8 +2179,10 @@
- end.
-
- get_node_config(Host, From, Node, Lang) ->
-- case catch mnesia:dirty_read(pubsub_node, {Host, Node}) of
-- [#pubsub_node{info = Info}] ->
-+ Table = get_table(Host),
-+ case catch mnesia:dirty_read(Table, {Host, Node}) of
-+ [N] ->
-+ Info = get_node_info(N),
- case get_affiliation(Info, From) of
- owner ->
- Fields = get_node_config_xfields(Node, Info, Lang),
-@@ -1384,7 +2194,7 @@
- {"type", "form"}],
- Fields}]}]}]};
- _ ->
-- {error, ?ERR_NOT_AUTHORIZED}
-+ {error, ?ERR_FORBIDDEN}
- end;
- _ ->
- {error, ?ERR_ITEM_NOT_FOUND}
-@@ -1416,7 +2226,7 @@
- [atom_to_list(O) || O <- Opts])).
-
-
---define(DEFAULT_OPTIONS,
-+-define(DEFAULT_PUBSUB_OPTIONS,
- [{deliver_payloads, true},
- {notify_config, false},
- {notify_delete, false},
-@@ -1424,12 +2234,28 @@
- {persist_items, true},
- {max_items, ?MAXITEMS div 2},
- {subscribe, true},
-- {subscription_model, open},
-+ {access_model, open},
-+ {access_roster_groups, []},
- {publish_model, publishers},
- {max_payload_size, ?MAX_PAYLOAD_SIZE},
-- {send_item_subscribe, false},
-+ {send_last_published_item, never},
- {presence_based_delivery, false}]).
-
-+-define(DEFAULT_PEP_OPTIONS,
-+ [{deliver_payloads, true},
-+ {notify_config, false},
-+ {notify_delete, false},
-+ {notify_retract, false},
-+ {persist_items, false},
-+ {max_items, ?MAXITEMS div 2},
-+ {subscribe, true},
-+ {access_model, presence},
-+ {access_roster_groups, []},
-+ {publish_model, publishers},
-+ {max_payload_size, ?MAX_PAYLOAD_SIZE},
-+ {send_last_published_item, on_sub_and_presence},
-+ {presence_based_delivery, true}]).
-+
- get_node_option(Info, current_approver) ->
- Default = hd(get_owners_jids(Info)),
- Options = Info#nodeinfo.options,
-@@ -1438,15 +2264,32 @@
- current_approver, 1,
- Options ++ [{current_approver, Default}])));
- get_node_option(#nodeinfo{options = Options}, Var) ->
-+ %% At this level, it's hard to know which set of defaults to
-+ %% apply. Therefore, all newly created nodes have an extra
-+ %% "defaults" field. We assume that all nodes created before this
-+ %% change are pubsub nodes.
-+ {Defaults, Opts} = case Options of
-+ [{defaults, pubsub_node} | Tail] ->
-+ {?DEFAULT_PUBSUB_OPTIONS, Tail};
-+ [{defaults, pep_node} | Tail] ->
-+ {?DEFAULT_PEP_OPTIONS, Tail};
-+ _ ->
-+ {?DEFAULT_PUBSUB_OPTIONS, Options}
-+ end,
- element(
-- 2, element(2, lists:keysearch(Var, 1, Options ++ ?DEFAULT_OPTIONS))).
-+ 2, element(2, lists:keysearch(Var, 1, Opts ++ Defaults))).
-
- get_max_items(Info) ->
- case get_node_option(Info, persist_items) of
- true ->
- get_node_option(Info, max_items);
- false ->
-- 0
-+ case get_node_option(Info, send_last_published_item) of
-+ never ->
-+ 0;
-+ _ ->
-+ 1
-+ end
- end.
-
- get_owners_jids(Info) ->
-@@ -1454,8 +2297,7 @@
- Owners =
- ?DICT:fold(
- fun(JID,
-- #entity{affiliation = Affiliation,
-- subscription = Subscription},
-+ #entity{affiliation = Affiliation},
- Acc) ->
- case Affiliation of
- owner ->
-@@ -1467,7 +2309,11 @@
- lists:sort(Owners).
-
-
--get_node_config_xfields(Node, Info, Lang) ->
-+get_node_config_xfields(_Node, Info, Lang) ->
-+ Type = case Info#nodeinfo.options of
-+ [{defaults, D} | _] -> D;
-+ _ -> pubsub_node
-+ end,
- [?XFIELD("hidden", "", "FORM_TYPE", ?NS_PUBSUB_NODE_CONFIG),
- ?BOOL_CONFIG_FIELD("Deliver payloads with event notifications", deliver_payloads),
- ?BOOL_CONFIG_FIELD("Notify subscribers when the node configuration changes", notify_config),
-@@ -1476,12 +2322,24 @@
- ?BOOL_CONFIG_FIELD("Persist items to storage", persist_items),
- ?INTEGER_CONFIG_FIELD("Max # of items to persist", max_items),
- ?BOOL_CONFIG_FIELD("Whether to allow subscriptions", subscribe),
-- ?ALIST_CONFIG_FIELD("Specify the subscriber model", subscription_model,
-- [open]),
-+ ?ALIST_CONFIG_FIELD("Specify the access model", access_model,
-+ [open, whitelist] ++
-+ case Type of
-+ pep_node -> [presence, roster];
-+ pubsub_node -> [authorize]
-+ end),
-+ %% XXX: change to list-multi, include current roster groups as options
-+ {xmlelement, "field", [{"type", "text-multi"},
-+ {"label", translate:translate(Lang, "Roster groups that may subscribe (if access model is roster)")},
-+ {"var", "pubsub#access_roster_groups"}],
-+ [{xmlelement, "value", [], [{xmlcdata, Value}]} ||
-+ Value <- get_node_option(Info, access_roster_groups)]},
- ?ALIST_CONFIG_FIELD("Specify the publisher model", publish_model,
- [publishers, subscribers, open]),
- ?INTEGER_CONFIG_FIELD("Max payload size in bytes", max_payload_size),
-- ?BOOL_CONFIG_FIELD("Send items to new subscribers", send_item_subscribe),
-+ %% XXX: fix labels for options
-+ ?ALIST_CONFIG_FIELD("When to send the last published item", send_last_published_item,
-+ [never, on_sub, on_sub_and_presence]),
- ?BOOL_CONFIG_FIELD("Only deliver notifications to available users", presence_based_delivery),
- ?JLIST_CONFIG_FIELD("Specify the current subscription approver", current_approver,
- get_owners_jids(Info))
-@@ -1489,8 +2347,10 @@
-
-
- set_node_config(Host, From, Node, Els, Lang) ->
-- case catch mnesia:dirty_read(pubsub_node, {Host, Node}) of
-- [#pubsub_node{info = Info} = N] ->
-+ Table = get_table(Host),
-+ case catch mnesia:dirty_read(Table, {Host, Node}) of
-+ [N] ->
-+ Info = get_node_info(N),
- case get_affiliation(Info, From) of
- owner ->
- case xml:remove_cdata(Els) of
-@@ -1510,14 +2370,14 @@
- {error, ?ERR_BAD_REQUEST}
- end;
- _ ->
-- {error, ?ERR_NOT_AUTHORIZED}
-+ {error, ?ERR_FORBIDDEN}
- end;
- _ ->
- {error, ?ERR_ITEM_NOT_FOUND}
- end.
-
-
--set_node_config1(Host, From, Node, XEl, CurOpts, Lang) ->
-+set_node_config1(Host, _From, Node, XEl, CurOpts, Lang) ->
- XData = jlib:parse_xdata_submit(XEl),
- case XData of
- invalid ->
-@@ -1537,78 +2397,97 @@
-
-
- -define(SET_BOOL_XOPT(Opt, Val),
-- case Val of
-- "0" -> set_xoption(Opts, add_opt(Opt, false, NewOpts));
-- "1" -> set_xoption(Opts, add_opt(Opt, true, NewOpts));
-- _ -> {error, ?ERR_BAD_REQUEST}
-+ BoolVal = case Val of
-+ "0" -> false;
-+ "1" -> true;
-+ "false" -> false;
-+ "true" -> true;
-+ _ -> error
-+ end,
-+ case BoolVal of
-+ error -> {error, ?ERR_NOT_ACCEPTABLE};
-+ _ -> set_xoption(Opts, add_opt(Opt, BoolVal, NewOpts), Type)
- end).
-
- -define(SET_STRING_XOPT(Opt, Val),
-- set_xoption(Opts, add_opt(Opt, Val, NewOpts))).
-+ set_xoption(Opts, add_opt(Opt, Val, NewOpts), Type)).
-
- -define(SET_INTEGER_XOPT(Opt, Val, Min, Max),
- case catch list_to_integer(Val) of
- IVal when is_integer(IVal),
- IVal >= Min,
- IVal =< Max ->
-- set_xoption(Opts, add_opt(Opt, IVal, NewOpts));
-+ set_xoption(Opts, add_opt(Opt, IVal, NewOpts), Type);
- _ ->
-- {error, ?ERR_BAD_REQUEST}
-+ {error, ?ERR_NOT_ACCEPTABLE}
- end).
-
- -define(SET_ALIST_XOPT(Opt, Val, Vals),
- case lists:member(Val, [atom_to_list(V) || V <- Vals]) of
- true ->
-- set_xoption(Opts, add_opt(Opt, list_to_atom(Val), NewOpts));
-+ set_xoption(Opts, add_opt(Opt, list_to_atom(Val), NewOpts), Type);
- false ->
-- {error, ?ERR_BAD_REQUEST}
-+ {error, ?ERR_NOT_ACCEPTABLE}
- end).
-
-
--set_xoption([], NewOpts) ->
-+set_xoption(Opts, [{defaults, Type} = Defaults | NewOpts]) ->
-+ %% Make sure that "defaults" remains at head of option list.
-+ [Defaults | set_xoption(Opts, NewOpts, Type)];
-+set_xoption(Opts, NewOpts) ->
-+ set_xoption(Opts, NewOpts, pubsub_node).
-+
-+set_xoption([], NewOpts, _Type) ->
- NewOpts;
--set_xoption([{"FORM_TYPE", _} | Opts], NewOpts) ->
-- set_xoption(Opts, NewOpts);
--set_xoption([{"pubsub#deliver_payloads", [Val]} | Opts], NewOpts) ->
-+set_xoption([{"FORM_TYPE", _} | Opts], NewOpts, Type) ->
-+ set_xoption(Opts, NewOpts, Type);
-+set_xoption([{"pubsub#deliver_payloads", [Val]} | Opts], NewOpts, Type) ->
- ?SET_BOOL_XOPT(deliver_payloads, Val);
--set_xoption([{"pubsub#notify_config", [Val]} | Opts], NewOpts) ->
-+set_xoption([{"pubsub#notify_config", [Val]} | Opts], NewOpts, Type) ->
- ?SET_BOOL_XOPT(notify_config, Val);
--set_xoption([{"pubsub#notify_delete", [Val]} | Opts], NewOpts) ->
-+set_xoption([{"pubsub#notify_delete", [Val]} | Opts], NewOpts, Type) ->
- ?SET_BOOL_XOPT(notify_delete, Val);
--set_xoption([{"pubsub#notify_retract", [Val]} | Opts], NewOpts) ->
-+set_xoption([{"pubsub#notify_retract", [Val]} | Opts], NewOpts, Type) ->
- ?SET_BOOL_XOPT(notify_retract, Val);
--set_xoption([{"pubsub#persist_items", [Val]} | Opts], NewOpts) ->
-+set_xoption([{"pubsub#persist_items", [Val]} | Opts], NewOpts, Type) ->
- ?SET_BOOL_XOPT(persist_items, Val);
--set_xoption([{"pubsub#max_items", [Val]} | Opts], NewOpts) ->
-+set_xoption([{"pubsub#max_items", [Val]} | Opts], NewOpts, Type) ->
- ?SET_INTEGER_XOPT(max_items, Val, 0, ?MAXITEMS);
--set_xoption([{"pubsub#subscribe", [Val]} | Opts], NewOpts) ->
-+set_xoption([{"pubsub#subscribe", [Val]} | Opts], NewOpts, Type) ->
- ?SET_BOOL_XOPT(subscribe, Val);
--set_xoption([{"pubsub#subscription_model", [Val]} | Opts], NewOpts) ->
-- ?SET_ALIST_XOPT(subscription_model, Val, [open]);
--set_xoption([{"pubsub#publish_model", [Val]} | Opts], NewOpts) ->
-+set_xoption([{"pubsub#access_model", [Val]} | Opts], NewOpts, Type) ->
-+ AllowedModels = case Type of
-+ pubsub_node -> [open, authorize, whitelist];
-+ pep_node -> [open, presence, roster, whitelist]
-+ end,
-+ ?SET_ALIST_XOPT(access_model, Val, AllowedModels);
-+set_xoption([{"pubsub#access_roster_groups", Values} | Opts], NewOpts, Type) ->
-+ set_xoption(Opts, add_opt(access_roster_groups, Values, NewOpts), Type);
-+set_xoption([{"pubsub#publish_model", [Val]} | Opts], NewOpts, Type) ->
- ?SET_ALIST_XOPT(publish_model, Val, [publishers, subscribers, open]);
--set_xoption([{"pubsub#max_payload_size", [Val]} | Opts], NewOpts) ->
-+set_xoption([{"pubsub#max_payload_size", [Val]} | Opts], NewOpts, Type) ->
- ?SET_INTEGER_XOPT(max_payload_size, Val, 0, ?MAX_PAYLOAD_SIZE);
--set_xoption([{"pubsub#send_item_subscribe", [Val]} | Opts], NewOpts) ->
-- ?SET_BOOL_XOPT(send_item_subscribe, Val);
--set_xoption([{"pubsub#presence_based_delivery", [Val]} | Opts], NewOpts) ->
-+set_xoption([{"pubsub#send_last_published_item", [Val]} | Opts], NewOpts, Type) ->
-+ ?SET_ALIST_XOPT(send_last_published_item, Val, [never, on_sub, on_sub_and_presence]);
-+set_xoption([{"pubsub#presence_based_delivery", [Val]} | Opts], NewOpts, Type) ->
- ?SET_BOOL_XOPT(presence_based_delivery, Val);
--set_xoption([{"pubsub#current_approver", _} | Opts], NewOpts) ->
-+set_xoption([{"pubsub#current_approver", _} | Opts], NewOpts, Type) ->
- % TODO
-- set_xoption(Opts, NewOpts);
-+ set_xoption(Opts, NewOpts, Type);
- %set_xoption([{"title", [Val]} | Opts], NewOpts) ->
- % ?SET_STRING_XOPT(title, Val);
--set_xoption([_ | _Opts], _NewOpts) ->
-- {error, ?ERR_BAD_REQUEST}.
-+set_xoption([_ | _Opts], _NewOpts, _Type) ->
-+ {error, ?ERR_NOT_ACCEPTABLE}.
-
-
- change_node_opts(Host, NewOpts, Node, Lang) ->
-+ Table = get_table(Host),
- F = fun() ->
-- case mnesia:read({pubsub_node, {Host, Node}}) of
-- [#pubsub_node{info = Info} = N] ->
-- NewInfo = Info#nodeinfo{options = NewOpts},
-- mnesia:write(
-- N#pubsub_node{info = NewInfo}),
-+ case mnesia:read({Table, {Host, Node}}) of
-+ [N] ->
-+ Info = get_node_info(N),
-+ NewInfo = Info#nodeinfo{options = maybe_add_defaults(NewOpts, Table)},
-+ mnesia:write(set_node_info(N, NewInfo)),
- {result, []};
- [] ->
- {error, ?ERR_ITEM_NOT_FOUND}
-@@ -1624,29 +2503,33 @@
- {error, ?ERR_INTERNAL_SERVER_ERROR}
- end.
-
-+maybe_add_defaults(NewOpts, Table) ->
-+ %% When we change node configuration, we add an explicit default
-+ %% marker, pubsub_node or pep_node.
-+ case NewOpts of
-+ [{defaults, _} | _] ->
-+ NewOpts;
-+ _ ->
-+ [{defaults, Table} | NewOpts]
-+ end.
-
-
-+get_present_resources({ToUser, ToServer, _}, {FromUser, FromServer, _}) ->
-+ get_present_resources(ToUser, ToServer, FromUser, FromServer).
-+
-+get_present_resources(ToUser, ToServer, FromUser, FromServer) ->
-+ %% Return a list of resources of FromUser@FromServer that have
-+ %% sent presence to ToUser@ToServer.
-+ Key = {ToUser, ToServer, FromUser, FromServer},
-+ lists:map(fun(#pubsub_presence{resource = Res}) -> Res end,
-+ case catch mnesia:dirty_read(pubsub_presence, Key) of
-+ Result when is_list(Result) ->
-+ Result;
-+ _ ->
-+ []
-+ end).
-
-
--find_my_host(LServer) ->
-- Parts = string:tokens(LServer, "."),
-- find_my_host(Parts, ?MYHOSTS).
--
--find_my_host([], _Hosts) ->
-- ?MYNAME;
--find_my_host([_ | Tail] = Parts, Hosts) ->
-- Domain = parts_to_string(Parts),
-- case lists:member(Domain, Hosts) of
-- true ->
-- Domain;
-- false ->
-- find_my_host(Tail, Hosts)
-- end.
--
--parts_to_string(Parts) ->
-- string:strip(lists:flatten(lists:map(fun(S) -> [S, $.] end, Parts)),
-- right, $.).
--
-
-
- update_table(Host) ->