Compare commits
461 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e4ec23919d | |||
| 1c095b609a | |||
| a819514e43 | |||
| 16cd93d587 | |||
| a8e5984f5f | |||
| 1a45637860 | |||
| 8cb3f61f88 | |||
| 4bc4f54e43 | |||
| 08774b1b5a | |||
| 300e765e20 | |||
| 951599be21 | |||
| 8bea14837e | |||
| 09250d6121 | |||
| 5968b35320 | |||
| f364fcda56 | |||
| 170874e115 | |||
| bec499a4a1 | |||
| d6709bd53a | |||
| 1cd1dd9f23 | |||
| af198dbe92 | |||
| 80ff4ad3d3 | |||
| 6e1691e2fa | |||
| e52c324a5e | |||
| e7b1f21e1c | |||
| a2d2581199 | |||
| eedd9496e4 | |||
| 3d4775d555 | |||
| 7f11f4a1fb | |||
| 612f15ab17 | |||
| af9ff6f1a1 | |||
| 9664de5242 | |||
| b13c51c8cf | |||
| 8229ee8dd8 | |||
| 476acbfa44 | |||
| 23dd81d18c | |||
| f08595b0e5 | |||
| 50b8500bd5 | |||
| 1cacd48261 | |||
| cf11acc450 | |||
| 0c18dd7068 | |||
| 4e807d69e8 | |||
| a61b7b1d98 | |||
| a55c85252f | |||
| 0168e39bb3 | |||
| 8f8b6870a0 | |||
| dc7208ed1c | |||
| 60b0b918a6 | |||
| d9e2d4e6a9 | |||
| 8fc80178b6 | |||
| c801bd9411 | |||
| b9d5a3350d | |||
| 2bb0095a32 | |||
| eda360914e | |||
| 042172eae1 | |||
| 0eaab78f67 | |||
| 5ec65571f8 | |||
| 7bbc98b04c | |||
| eda6b80ece | |||
| 2ddb7be19a | |||
| 04f20a21fb | |||
| 40ae9b33ef | |||
| e2357ecd96 | |||
| 0116287405 | |||
| 6ee534b262 | |||
| 42f72a49b1 | |||
| 771acc3ac7 | |||
| 5706aaa89c | |||
| c17bbc8859 | |||
| 8f317c0059 | |||
| d1c654a7e1 | |||
| ae5c31b06d | |||
| b09cda5c17 | |||
| 7887392c1d | |||
| cc2b7d2832 | |||
| 0a69935b6b | |||
| 4b7c74415f | |||
| 418baf4fa6 | |||
| fcf647738d | |||
| 3c9ab9e53d | |||
| c339c9b2ad | |||
| 4ef32bb18f | |||
| 0f87034539 | |||
| acee58f6bb | |||
| ceeef24faa | |||
| 201b0b3725 | |||
| 5f8b41a357 | |||
| a003ef556b | |||
| cb91e10803 | |||
| 5190866a24 | |||
| 473a58e3c2 | |||
| 3e6b88cbc3 | |||
| 362d7f617d | |||
| d11df52abf | |||
| 906161b27f | |||
| 347e8b28ef | |||
| c85c2796f4 | |||
| df72de96ae | |||
| e1f8233d08 | |||
| 38d2a27c56 | |||
| 6a42119292 | |||
| 89787875d4 | |||
| d76ae701cd | |||
| c4db156ad2 | |||
| d95778ea16 | |||
| a9b452fba9 | |||
| afed9e919e | |||
| 5252dcbd2c | |||
| a5cfac76dd | |||
| 45aa32f6fe | |||
| 2372e30150 | |||
| f3b55596b2 | |||
| 84eee8d5a7 | |||
| a800a5d4df | |||
| dfa47556d1 | |||
| 77111aeec1 | |||
| c9ac75474f | |||
| 0fcaef0566 | |||
| 031c7412a8 | |||
| 594ff79514 | |||
| 8f3f74a6d7 | |||
| ff2050b301 | |||
| 89ea1dd1c4 | |||
| 66902b788b | |||
| ec8cb81c0d | |||
| 1a24ac62e5 | |||
| 78fb913a00 | |||
| e521c8368a | |||
| ac8c536b50 | |||
| 84d9ee07b4 | |||
| ab9ac62138 | |||
| beaf351ba4 | |||
| 37d3a4e1f5 | |||
| 566c046cd5 | |||
| df921fef40 | |||
| 56e7affdfd | |||
| bef66dba24 | |||
| e62af41fa8 | |||
| 472089a328 | |||
| c4d582ace4 | |||
| a4e320c263 | |||
| 7d3d008940 | |||
| 3be9c27509 | |||
| 3ef6e4c834 | |||
| a15e689386 | |||
| 7c8a452b00 | |||
| e5d202a0bf | |||
| 083dfe01ea | |||
| f0c745b916 | |||
| 9ff1a80db4 | |||
| 5480ee29fd | |||
| 0d4b0b4218 | |||
| cfe396e155 | |||
| 2163cbb22e | |||
| 6b3f228327 | |||
| e58e6a09dd | |||
| 2d05ddd466 | |||
| 975f4c56d4 | |||
| 8eef2f02bf | |||
| 2f7c69fd14 | |||
| 02eeebd41a | |||
| 99610c3357 | |||
| aad740f34c | |||
| a70c72e50e | |||
| a2fdc75730 | |||
| b82789f11d | |||
| 6b7d70adf6 | |||
| 10f10a2fd3 | |||
| 35c4e740ab | |||
| e3085a4d48 | |||
| e8d008c392 | |||
| 674ab27700 | |||
| 9442a583bc | |||
| 9787416e88 | |||
| fbe2995696 | |||
| 33251cd5a8 | |||
| f387934886 | |||
| fb39b163df | |||
| 011535f0de | |||
| 75d3152a0f | |||
| db8bd0126b | |||
| 545f9ce525 | |||
| 7f1e9d3972 | |||
| 431c34709c | |||
| cf6d67ceed | |||
| ef0cf5d3d7 | |||
| e99ecf6d06 | |||
| 83c7da3831 | |||
| 8dc4dd7f3b | |||
| 66b7caafe0 | |||
| 7c0b2f5425 | |||
| 4645885180 | |||
| 472d046426 | |||
| 613d175f37 | |||
| a63bbe8a23 | |||
| bc118986b7 | |||
| 8d8dee5acf | |||
| 92feebd0fa | |||
| 0b423eb287 | |||
| 7d7c739cb3 | |||
| 60d422eb8e | |||
| 52df4fa024 | |||
| 6ebebdd02d | |||
| e30e7686e3 | |||
| 290432c0ee | |||
| 6563267055 | |||
| ecf7b0282e | |||
| ea6e85d926 | |||
| b4d107301d | |||
| fead37d1c5 | |||
| eaecb9b65c | |||
| 2948cddebf | |||
| 438dc57def | |||
| 4d64fbb0ac | |||
| e0781d9217 | |||
| f04fe5f743 | |||
| 66a5aff323 | |||
| 5746c08f72 | |||
| 39acf823ef | |||
| 2ea9e6ed59 | |||
| 21c75ebce5 | |||
| 32e0a88edc | |||
| bd91e2da16 | |||
| f3d24b6a07 | |||
| d1377da151 | |||
| d471be26cf | |||
| 31f6a9e66e | |||
| d736c47649 | |||
| 0e4806820e | |||
| 3850b91571 | |||
| 7b0174a626 | |||
| 2270df86d9 | |||
| a04131c6d7 | |||
| e5830253b9 | |||
| b7a07087d1 | |||
| adf56dedf3 | |||
| 6bfd8b8e9a | |||
| 1babae067d | |||
| 3ae4797848 | |||
| 86f0a9790d | |||
| 54acf9bde4 | |||
| 8f27a697c0 | |||
| c9a712a16a | |||
| d6e81ac06b | |||
| b0b371d23a | |||
| dd772404c5 | |||
| bed5e80ef9 | |||
| 9ccdb5d78b | |||
| 5bef1a8f77 | |||
| 4f1637fa40 | |||
| 796cb6634b | |||
| bb5480756a | |||
| edb030f49a | |||
| 0ed4ceebea | |||
| 31f7eadfca | |||
| 1c72c45404 | |||
| f8fd9969e1 | |||
| 8d09655a89 | |||
| a06b627631 | |||
| cb41c8ef80 | |||
| d4cea0f78f | |||
| 4d20abd7b6 | |||
| 351ad528f9 | |||
| 006da5589e | |||
| 5f32dd3959 | |||
| a9269df2aa | |||
| a7d82d6ecb | |||
| 5b10b58c9f | |||
| ae24f7d787 | |||
| 1dfd9fd568 | |||
| f655ab2ffc | |||
| 302294faec | |||
| b6a637c121 | |||
| 60009ece44 | |||
| 41fad8956b | |||
| f0c32433dc | |||
| 78f50c58bf | |||
| 133b8d42a3 | |||
| 3785b3e951 | |||
| 70e1545d3a | |||
| 8aaf9bffa0 | |||
| d65b785f5d | |||
| 9aabd59a1f | |||
| 8806fdc1c2 | |||
| 1922bf21f0 | |||
| c98ddeb59f | |||
| 613214da18 | |||
| 38693a670b | |||
| a97a60a888 | |||
| 49365da481 | |||
| 70e84021f2 | |||
| 24e033ac79 | |||
| 658ab235ba | |||
| 2f16a160c0 | |||
| 4a2f62062e | |||
| 33d4126290 | |||
| 87315e92a8 | |||
| 494add4fd0 | |||
| 3b7458bbc2 | |||
| f05a4d1638 | |||
| 75d2cbcb14 | |||
| f9fa168d84 | |||
| 5ad1d08b89 | |||
| dcb068c7ad | |||
| 2d32d2f25e | |||
| 307e57a105 | |||
| 8e68e89816 | |||
| 1564060c6c | |||
| f39ccd73c5 | |||
| 01689bc6b9 | |||
| 024a80d41f | |||
| f485109c39 | |||
| bde46896d6 | |||
| 0c30b012f7 | |||
| 14b39a0ee4 | |||
| e380eee223 | |||
| 1959546ff9 | |||
| 92f5509b35 | |||
| 1a2e6b02ab | |||
| 56bf156b6f | |||
| 5632901820 | |||
| 92b6c12420 | |||
| 062d58026a | |||
| 7ef85dddea | |||
| 4a9e7f0a3a | |||
| cffe224d4a | |||
| 15c27c9ddd | |||
| 149f8e2b45 | |||
| 2ab31cb613 | |||
| 03870f962c | |||
| 405e9b24b0 | |||
| 3c51ca06d5 | |||
| 02cfb11a6d | |||
| 4e875c7fb7 | |||
| 21f2817f40 | |||
| 31e4ccf78b | |||
| bfedd21c98 | |||
| 9f3cdad3f7 | |||
| 931866ee33 | |||
| b3facf092a | |||
| 70c1e1d0b1 | |||
| aea394861d | |||
| 2e33904bb8 | |||
| 2d3bbd43d7 | |||
| 6c0e9ef575 | |||
| ca62271a89 | |||
| c96a1805e8 | |||
| babff870a8 | |||
| 5cd3de9cd7 | |||
| 437d8c6b7c | |||
| 440eef74e9 | |||
| c849552177 | |||
| 6134c67df4 | |||
| aa60140ba8 | |||
| 59135cac6f | |||
| 8d69d4aaba | |||
| 426b7ca769 | |||
| b61d16dd33 | |||
| 807af3c08a | |||
| d07424365d | |||
| 70fe2948b9 | |||
| a5166f3946 | |||
| 11b00b92e9 | |||
| c10e43f95f | |||
| eeffc77a1a | |||
| 254686ab46 | |||
| 4a6fc46713 | |||
| bde3bce1e7 | |||
| f76dcd0d48 | |||
| 7da8d9e4e3 | |||
| 3a7d02dbd3 | |||
| 350af319bf | |||
| f81473fc65 | |||
| b6dcd41225 | |||
| db2baa8f84 | |||
| a894d25b1f | |||
| a93991bef2 | |||
| 7127d067c8 | |||
| ba326eb976 | |||
| fd50b2169b | |||
| 00d8b2ac30 | |||
| cac23c39c9 | |||
| a5813b798f | |||
| 191cd2af3c | |||
| f2cfee11de | |||
| b0c79c57b0 | |||
| 8ea523889b | |||
| b44c462b0e | |||
| 0987700a27 | |||
| ff4f052bb1 | |||
| 100b821c1a | |||
| 893c47a2e0 | |||
| 694af69982 | |||
| c576f340f9 | |||
| 179a0cf255 | |||
| a45ecb70ff | |||
| df1ab9149f | |||
| cb54444f00 | |||
| c77e7fbb7d | |||
| 40625b29f2 | |||
| 2624f3ba51 | |||
| 44832e12b3 | |||
| caa8d0c411 | |||
| 7e72d18292 | |||
| b0a81778af | |||
| 652774a83c | |||
| 2aea503a2a | |||
| 0d8aacb3e7 | |||
| e6be70943f | |||
| c86e4faba3 | |||
| c3c06ccd1c | |||
| 18b569a356 | |||
| 261acfce54 | |||
| c8567f1de2 | |||
| 35a0e27d04 | |||
| 73f7b2ba38 | |||
| 8a693df6e6 | |||
| c41bdea1f1 | |||
| cccbf7de12 | |||
| 660a2735f0 | |||
| 77136bccdf | |||
| b8b6fc0da5 | |||
| 8ecf8d7e27 | |||
| 4134edf8de | |||
| a77d53d738 | |||
| 49a3424a26 | |||
| 92a60ff7fd | |||
| 33c7d36a95 | |||
| 6c7316cbdd | |||
| 09da9eeb95 | |||
| 76d4ba66b2 | |||
| f284fc3284 | |||
| 86a59fb469 | |||
| 31da259a75 | |||
| 363711a370 | |||
| bf98fa0c01 | |||
| cd923838c3 | |||
| a22ebd3c49 | |||
| 353d16b8ef | |||
| 6bb0dc12f1 | |||
| ad00ec1518 | |||
| c03140d4be | |||
| ea8aa1f25b | |||
| 8fe6ed011d | |||
| 35cde6787d | |||
| 23b28ec60f | |||
| 59ae9bea76 | |||
| 7be707f7bc | |||
| 200815dcdb | |||
| 2d1c416daf | |||
| 3aaebe98f4 | |||
| 2ee7642816 | |||
| bf63d09d80 | |||
| 28c4c87956 | |||
| d0b7cd599b | |||
| cc1839a250 | |||
| 7d37715f8b | |||
| 091b4568d5 | |||
| cc0503fd5e | |||
| 4862251f34 | |||
| 987d796439 | |||
| 628571f8cf |
-20
@@ -16,23 +16,3 @@
|
||||
/doc/*.toc
|
||||
/doc/contributed_modules.tex
|
||||
/doc/version.tex
|
||||
/src/*.beam
|
||||
/src/*.so
|
||||
/src/*.so.dSYM
|
||||
/src/*/*.beam
|
||||
/src/*/Makefile
|
||||
/src/Makefile
|
||||
/src/XmppAddr.asn1db
|
||||
/src/XmppAddr.erl
|
||||
/src/XmppAddr.hrl
|
||||
/src/aclocal.m4
|
||||
/src/autom4te.cache
|
||||
/src/config.log
|
||||
/src/config.status
|
||||
/src/ejabberd.init
|
||||
/src/ejabberdctl.example
|
||||
/src/eldap/ELDAPv3.asn1db
|
||||
/src/eldap/ELDAPv3.erl
|
||||
/src/eldap/ELDAPv3.hrl
|
||||
/src/eldap/eldap_filter_yecc.erl
|
||||
/src/epam
|
||||
|
||||
+238
@@ -0,0 +1,238 @@
|
||||
REBAR = @REBAR@
|
||||
INSTALL = @INSTALL@
|
||||
SED = @SED@
|
||||
ERL = @ERL@
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
|
||||
DESTDIR =
|
||||
|
||||
# /etc/ejabberd/
|
||||
ETCDIR = $(DESTDIR)@sysconfdir@/ejabberd
|
||||
|
||||
# /sbin/
|
||||
SBINDIR = $(DESTDIR)@sbindir@
|
||||
|
||||
# /lib/ejabberd/
|
||||
EJABBERDDIR = $(DESTDIR)@libdir@/ejabberd
|
||||
|
||||
# /share/doc/ejabberd
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
datarootdir = @datarootdir@
|
||||
DOCDIR = $(DESTDIR)@docdir@
|
||||
|
||||
# /usr/lib/ejabberd/ebin/
|
||||
BEAMDIR = $(EJABBERDDIR)/ebin
|
||||
|
||||
# /usr/lib/ejabberd/include/
|
||||
INCLUDEDIR = $(EJABBERDDIR)/include
|
||||
|
||||
# /usr/lib/ejabberd/priv/
|
||||
PRIVDIR = $(EJABBERDDIR)/priv
|
||||
|
||||
# /usr/lib/ejabberd/priv/bin
|
||||
PBINDIR = $(PRIVDIR)/bin
|
||||
|
||||
# /usr/lib/ejabberd/priv/lib
|
||||
SODIR = $(PRIVDIR)/lib
|
||||
|
||||
# /usr/lib/ejabberd/priv/msgs
|
||||
MSGSDIR = $(PRIVDIR)/msgs
|
||||
|
||||
# /var/lib/ejabberd/
|
||||
SPOOLDIR = $(DESTDIR)@localstatedir@/lib/ejabberd
|
||||
|
||||
# /var/lock/ejabberdctl
|
||||
CTLLOCKDIR = $(DESTDIR)@localstatedir@/lock/ejabberdctl
|
||||
|
||||
# /var/lib/ejabberd/.erlang.cookie
|
||||
COOKIEFILE = $(SPOOLDIR)/.erlang.cookie
|
||||
|
||||
# /var/log/ejabberd/
|
||||
LOGDIR = $(DESTDIR)@localstatedir@/log/ejabberd
|
||||
|
||||
INSTALLUSER=@INSTALLUSER@
|
||||
# if no user was enabled, don't set privileges or ownership
|
||||
ifeq ($(INSTALLUSER),)
|
||||
O_USER=
|
||||
G_USER=
|
||||
CHOWN_COMMAND=echo
|
||||
CHOWN_OUTPUT=/dev/null
|
||||
INIT_USER=root
|
||||
else
|
||||
O_USER=-o $(INSTALLUSER)
|
||||
G_USER=-g $(INSTALLUSER)
|
||||
CHOWN_COMMAND=chown
|
||||
CHOWN_OUTPUT=&1
|
||||
INIT_USER=$(INSTALLUSER)
|
||||
endif
|
||||
|
||||
all: deps src
|
||||
|
||||
deps:
|
||||
$(REBAR) get-deps
|
||||
|
||||
src:
|
||||
$(REBAR) compile
|
||||
|
||||
translations:
|
||||
contrib/extract_translations/prepare-translation.sh -updateall
|
||||
|
||||
doc:
|
||||
echo making $$target in doc; \
|
||||
(cd doc && $(MAKE) $$target) || exit 1
|
||||
|
||||
edoc:
|
||||
$(ERL) -noinput +B -eval \
|
||||
'case edoc:application(ejabberd, ".", []) of ok -> halt(0); error -> halt(1) end.'
|
||||
|
||||
install: all
|
||||
#
|
||||
# Configuration files
|
||||
$(INSTALL) -d -m 750 $(G_USER) $(ETCDIR)
|
||||
[ -f $(ETCDIR)/ejabberd.cfg ] \
|
||||
&& $(INSTALL) -b -m 640 $(G_USER) ejabberd.cfg.example $(ETCDIR)/ejabberd.cfg-new \
|
||||
|| $(INSTALL) -b -m 640 $(G_USER) ejabberd.cfg.example $(ETCDIR)/ejabberd.cfg
|
||||
$(SED) -e "s*{{rootdir}}*@prefix@*" \
|
||||
-e "s*{{installuser}}*@INSTALLUSER@*" \
|
||||
-e "s*{{libdir}}*@libdir@*" \
|
||||
-e "s*{{sysconfdir}}*@sysconfdir@*" \
|
||||
-e "s*{{localstatedir}}*@localstatedir@*" \
|
||||
-e "s*{{docdir}}*@docdir@*" \
|
||||
-e "s*{{erl}}*@ERL@*" ejabberdctl.template \
|
||||
> ejabberdctl.example
|
||||
[ -f $(ETCDIR)/ejabberdctl.cfg ] \
|
||||
&& $(INSTALL) -b -m 640 $(G_USER) ejabberdctl.cfg.example $(ETCDIR)/ejabberdctl.cfg-new \
|
||||
|| $(INSTALL) -b -m 640 $(G_USER) ejabberdctl.cfg.example $(ETCDIR)/ejabberdctl.cfg
|
||||
$(INSTALL) -b -m 644 $(G_USER) inetrc $(ETCDIR)/inetrc
|
||||
#
|
||||
# Administration script
|
||||
[ -d $(SBINDIR) ] || $(INSTALL) -d -m 755 $(SBINDIR)
|
||||
$(INSTALL) -m 550 $(G_USER) ejabberdctl.example $(SBINDIR)/ejabberdctl
|
||||
#
|
||||
# Init script
|
||||
$(SED) -e "s*@ctlscriptpath@*$(SBINDIR)*" \
|
||||
-e "s*@installuser@*$(INIT_USER)*" ejabberd.init.template \
|
||||
> ejabberd.init
|
||||
chmod 755 ejabberd.init
|
||||
#
|
||||
# Binary Erlang files
|
||||
$(INSTALL) -d $(BEAMDIR)
|
||||
$(INSTALL) -m 644 ebin/*.app $(BEAMDIR)
|
||||
$(INSTALL) -m 644 ebin/*.beam $(BEAMDIR)
|
||||
$(INSTALL) -m 644 deps/*/ebin/*.app $(BEAMDIR)
|
||||
$(INSTALL) -m 644 deps/*/ebin/*.beam $(BEAMDIR)
|
||||
rm -f $(BEAMDIR)/configure.beam
|
||||
#
|
||||
# ejabberd header files
|
||||
$(INSTALL) -d $(INCLUDEDIR)
|
||||
$(INSTALL) -m 644 include/*.hrl $(INCLUDEDIR)
|
||||
$(INSTALL) -m 644 deps/*/include/*.hrl $(INCLUDEDIR)
|
||||
#
|
||||
# Binary C programs
|
||||
$(INSTALL) -d $(PBINDIR)
|
||||
$(INSTALL) -m 750 $(O_USER) tools/captcha.sh $(PBINDIR)
|
||||
#
|
||||
# Binary system libraries
|
||||
$(INSTALL) -d $(SODIR)
|
||||
#$(INSTALL) -m 644 priv/lib/*.so $(SODIR)
|
||||
$(INSTALL) -m 644 deps/*/priv/lib/*.so $(SODIR)
|
||||
#
|
||||
# Translated strings
|
||||
$(INSTALL) -d $(MSGSDIR)
|
||||
$(INSTALL) -m 644 priv/msgs/*.msg $(MSGSDIR)
|
||||
#
|
||||
# Spool directory
|
||||
$(INSTALL) -d -m 750 $(O_USER) $(SPOOLDIR)
|
||||
$(CHOWN_COMMAND) -R @INSTALLUSER@ $(SPOOLDIR) >$(CHOWN_OUTPUT)
|
||||
chmod -R 750 $(SPOOLDIR)
|
||||
[ ! -f $(COOKIEFILE) ] || { $(CHOWN_COMMAND) @INSTALLUSER@ $(COOKIEFILE) >$(CHOWN_OUTPUT) ; chmod 400 $(COOKIEFILE) ; }
|
||||
#
|
||||
# ejabberdctl lock directory
|
||||
$(INSTALL) -d -m 750 $(O_USER) $(CTLLOCKDIR)
|
||||
$(CHOWN_COMMAND) -R @INSTALLUSER@ $(CTLLOCKDIR) >$(CHOWN_OUTPUT)
|
||||
chmod -R 750 $(CTLLOCKDIR)
|
||||
#
|
||||
# Log directory
|
||||
$(INSTALL) -d -m 750 $(O_USER) $(LOGDIR)
|
||||
$(CHOWN_COMMAND) -R @INSTALLUSER@ $(LOGDIR) >$(CHOWN_OUTPUT)
|
||||
chmod -R 750 $(LOGDIR)
|
||||
#
|
||||
# Documentation
|
||||
$(INSTALL) -d $(DOCDIR)
|
||||
$(INSTALL) -m 644 doc/dev.html $(DOCDIR)
|
||||
$(INSTALL) -m 644 doc/guide.html $(DOCDIR)
|
||||
$(INSTALL) -m 644 doc/*.png $(DOCDIR)
|
||||
$(INSTALL) -m 644 doc/*.txt $(DOCDIR)
|
||||
[ -f doc/guide.pdf ] \
|
||||
&& $(INSTALL) -m 644 doc/guide.pdf $(DOCDIR) \
|
||||
|| echo "No doc/guide.pdf was built"
|
||||
$(INSTALL) -m 644 COPYING $(DOCDIR)
|
||||
|
||||
uninstall: uninstall-binary
|
||||
|
||||
uninstall-binary:
|
||||
rm -f $(SBINDIR)/ejabberdctl
|
||||
rm -fr $(DOCDIR)
|
||||
rm -f $(BEAMDIR)/*.beam
|
||||
rm -f $(BEAMDIR)/*.app
|
||||
rm -fr $(BEAMDIR)
|
||||
rm -f $(INCLUDEDIR)/*.hrl
|
||||
rm -fr $(INCLUDEDIR)
|
||||
rm -fr $(PBINDIR)
|
||||
rm -f $(SODIR)/*.so
|
||||
rm -fr $(SODIR)
|
||||
rm -f $(MSGSDIR)/*.msgs
|
||||
rm -fr $(MSGSDIR)
|
||||
rm -fr $(PRIVDIR)
|
||||
rm -fr $(EJABBERDDIR)
|
||||
|
||||
uninstall-all: uninstall-binary
|
||||
rm -rf $(ETCDIR)
|
||||
rm -rf $(EJABBERDDIR)
|
||||
rm -rf $(SPOOLDIR)
|
||||
rm -rf $(CTLLOCKDIR)
|
||||
rm -rf $(LOGDIR)
|
||||
|
||||
clean:
|
||||
$(REBAR) clean
|
||||
|
||||
clean-rel:
|
||||
rm -rf rel/ejabberd
|
||||
|
||||
distclean: clean clean-rel
|
||||
rm -f config.status
|
||||
rm -f config.log
|
||||
rm -rf autom4te.cache
|
||||
rm -rf deps
|
||||
rm -rf ebin
|
||||
rm -f Makefile
|
||||
rm -f vars.config
|
||||
rm -f src/ejabberd.app.src
|
||||
[ ! -f ../ChangeLog ] || rm -f ../ChangeLog
|
||||
|
||||
rel: all
|
||||
$(REBAR) generate
|
||||
|
||||
TAGS:
|
||||
etags *.erl
|
||||
|
||||
Makefile: Makefile.in
|
||||
|
||||
deps := $(filter-out deps/riak_pb/ebin, $(wildcard deps/*/ebin))
|
||||
|
||||
erlang.plt:
|
||||
-dialyzer --build_plt --output_plt erlang.plt \
|
||||
--apps kernel stdlib sasl crypto public_key ssl mnesia \
|
||||
inets odbc tools compiler erts webtool runtime_tools asn1 \
|
||||
observer xmerl et gs wx syntax_tools $(deps)
|
||||
|
||||
plt: erlang.plt
|
||||
|
||||
dialyzer: plt
|
||||
-dialyzer --plt erlang.plt --add_to_plt --output_plt ejabberd.plt \
|
||||
--get_warnings -o dialyzer.log ebin
|
||||
|
||||
.PHONY: src doc edoc dialyzer Makefile TAGS clean clean-rel distclean rel plt \
|
||||
install uninstall uninstall-binary uninstall-all translations
|
||||
@@ -59,6 +59,8 @@ release : build release_clean
|
||||
copy mod_muc\*.erl $(SRC_DIR)\mod_muc
|
||||
mkdir $(SRC_DIR)\mod_pubsub
|
||||
copy mod_pubsub\*.erl $(SRC_DIR)\mod_pubsub
|
||||
mkdir $(SRC_DIR)\mod_pubsub_ng
|
||||
copy mod_pubsub_ng\*.erl $(SRC_DIR)\mod_pubsub_ng
|
||||
mkdir $(SRC_DIR)\mod_proxy65
|
||||
copy mod_proxy65\*.erl $(SRC_DIR)\mod_proxy65
|
||||
copy mod_proxy65\*.hrl $(SRC_DIR)\mod_proxy65
|
||||
@@ -100,6 +102,8 @@ all-recursive :
|
||||
nmake -nologo -f Makefile.win32
|
||||
cd ..\mod_pubsub
|
||||
nmake -nologo -f Makefile.win32
|
||||
cd ..\mod_pubsub_ng
|
||||
nmake -nologo -f Makefile.win32
|
||||
cd ..\mod_proxy65
|
||||
nmake -nologo -f Makefile.win32
|
||||
cd ..\stringprep
|
||||
@@ -143,6 +147,8 @@ clean-recursive :
|
||||
nmake -nologo -f Makefile.win32 clean
|
||||
cd ..\mod_pubsub
|
||||
nmake -nologo -f Makefile.win32 clean
|
||||
cd ..\mod_pubsub_ng
|
||||
nmake -nologo -f Makefile.win32 clean
|
||||
cd ..\mod_proxy65
|
||||
nmake -nologo -f Makefile.win32 clean
|
||||
cd ..\stringprep
|
||||
@@ -14,8 +14,6 @@ To compile ejabberd you need:
|
||||
- OpenSSL 0.9.8 or higher, for STARTTLS, SASL and SSL encryption.
|
||||
- Zlib 1.2.3 or higher, for Stream Compression support
|
||||
(XEP-0138). Optional.
|
||||
- Erlang mysql library. Optional. MySQL authentication/storage.
|
||||
- Erlang pgsql library. Optional. PostgreSQL authentication/storage.
|
||||
- PAM library. Optional. For Pluggable Authentication Modules (PAM).
|
||||
- GNU Iconv 1.8 or higher, for the IRC Transport
|
||||
(mod_irc). Optional. Not needed on systems with GNU Libc.
|
||||
@@ -25,7 +23,7 @@ To compile ejabberd you need:
|
||||
|
||||
1. Compile and install on *nix systems
|
||||
|
||||
To compile ejabberd, go to the directory src/ and execute the commands:
|
||||
To compile ejabberd execute the commands:
|
||||
./configure
|
||||
make
|
||||
|
||||
|
||||
Vendored
+1538
-3227
File diff suppressed because it is too large
Load Diff
+266
@@ -0,0 +1,266 @@
|
||||
# -*- Autoconf -*-
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ(2.53)
|
||||
AC_PACKAGE_VERSION(3.0.0)
|
||||
AC_INIT(ejabberd, 3.0.0, [ejabberd@process-one.net], [ejabberd])
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_MAKE_SET
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_SED
|
||||
|
||||
if test "x$GCC" = "xyes"; then
|
||||
CFLAGS="$CFLAGS -Wall"
|
||||
fi
|
||||
|
||||
# Checks Erlang runtime and compiler
|
||||
AC_ERLANG_NEED_ERL
|
||||
AC_ERLANG_NEED_ERLC
|
||||
|
||||
# Checks and sets ERLANG_ROOT_DIR and ERLANG_LIB_DIR variable
|
||||
# AC_ERLANG_SUBST_ROOT_DIR
|
||||
# AC_ERLANG_SUBST_LIB_DIR
|
||||
|
||||
#locating escript
|
||||
AC_PATH_PROG([ESCRIPT], [escript], [])
|
||||
|
||||
#locating rebar
|
||||
AC_PATH_PROG([REBAR], [rebar], [./rebar])
|
||||
|
||||
#locating make
|
||||
AC_CHECK_PROG([MAKE], [make], [make], [])
|
||||
|
||||
if test "x$ESCRIPT" = "x"; then
|
||||
AC_MSG_ERROR(['escript' was not found])
|
||||
fi
|
||||
|
||||
if test "x$MAKE" = "x"; then
|
||||
AC_MSG_ERROR(['make' was not found])
|
||||
fi
|
||||
|
||||
# Change default prefix
|
||||
AC_PREFIX_DEFAULT(/)
|
||||
|
||||
AC_ARG_ENABLE(hipe,
|
||||
[AC_HELP_STRING([--enable-hipe], [compile natively with HiPE, not recommended (default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) hipe=true ;;
|
||||
no) hipe=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-hipe) ;;
|
||||
esac],[hipe=false])
|
||||
|
||||
AC_ARG_ENABLE(roster_gateway_workaround,
|
||||
[AC_HELP_STRING([--enable-roster-gateway-workaround], [turn on workaround for processing gateway subscriptions (default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) roster_gateway_workaround=true ;;
|
||||
no) roster_gateway_workaround=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-roster-gateway-workaround) ;;
|
||||
esac],[roster_gateway_workaround=false])
|
||||
|
||||
AC_ARG_ENABLE(flash_hack,
|
||||
[AC_HELP_STRING([--enable-flash-hack], [support Adobe Flash client XML (default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) flash_hack=true ;;
|
||||
no) flash_hack=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-flash-hack) ;;
|
||||
esac],[flash_hack=false])
|
||||
|
||||
AC_ARG_ENABLE(transient_supervisors,
|
||||
[AC_HELP_STRING([--enable-transient_supervisors], [use Erlang supervision for transient process (default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) transient_supervisors=true ;;
|
||||
no) transient_supervisors=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-transient_supervisors) ;;
|
||||
esac],[transient_supervisors=false])
|
||||
|
||||
AC_ARG_ENABLE(full_xml,
|
||||
[AC_HELP_STRING([--enable-full-xml], [use XML features in XMPP stream (ex: CDATA) (default: no, requires XML compliant clients)])],
|
||||
[case "${enableval}" in
|
||||
yes) full_xml=true ;;
|
||||
no) full_xml=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-full-xml) ;;
|
||||
esac],[full_xml=false])
|
||||
|
||||
AC_ARG_ENABLE(mssql,
|
||||
[AC_HELP_STRING([--enable-mssql], [use Microsoft SQL Server database (default: no, requires --enable-odbc)])],
|
||||
[case "${enableval}" in
|
||||
yes) db_type=mssql ;;
|
||||
no) db_type=generic ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-mssql) ;;
|
||||
esac],[db_type=generic])
|
||||
|
||||
AC_ARG_ENABLE(tools,
|
||||
[AC_HELP_STRING([--enable-tools], [build development tools (currently the ejabberd profiler only, default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) tools=true ;;
|
||||
no) tools=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-tools) ;;
|
||||
esac],[tools=false])
|
||||
|
||||
AC_ARG_ENABLE(all,
|
||||
[AC_HELP_STRING([--enable-all], [same as --enable-nif --enable-mysql --enable-pgsql --enable-pam --enable-zlib --enable-stun --enable-riak --enable-json --enable-iconv --enable-debug --enable-pubsub-ng --enable-http (useful for Dialyzer checks, default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) nif=true mysql=true pgsql=true pam=true zlib=true stun=true riak=true json=true iconv=true debug=true pubsub_ng=true http=true ;;
|
||||
no) nif=false mysql=false pgsql=false pam=false zlib=false stun=false riak=false json=false iconv=false debug=false pubsub_ng=false http=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-all) ;;
|
||||
esac],[])
|
||||
|
||||
AC_ARG_ENABLE(nif,
|
||||
[AC_HELP_STRING([--enable-nif], [replace some functions with C equivalents. Requires Erlang R13B04 or higher (default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) nif=true ;;
|
||||
no) nif=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-nif) ;;
|
||||
esac],[if test "x$nif" = "x"; then nif=false; fi])
|
||||
|
||||
AC_ARG_ENABLE(mysql,
|
||||
[AC_HELP_STRING([--enable-mysql], [enable MySQL support (default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) mysql=true ;;
|
||||
no) mysql=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-mysql) ;;
|
||||
esac],[if test "x$mysql" = "x"; then mysql=false; fi])
|
||||
|
||||
AC_ARG_ENABLE(pgsql,
|
||||
[AC_HELP_STRING([--enable-pgsql], [enable PostgreSQL support (default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) pgsql=true ;;
|
||||
no) pgsql=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-pgsql) ;;
|
||||
esac],[if test "x$pgsql" = "x"; then pgsql=false; fi])
|
||||
|
||||
AC_ARG_ENABLE(pam,
|
||||
[AC_HELP_STRING([--enable-pam], [enable PAM support (default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) pam=true ;;
|
||||
no) pam=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-pam) ;;
|
||||
esac],[if test "x$pam" = "x"; then pam=false; fi])
|
||||
|
||||
AC_ARG_ENABLE(zlib,
|
||||
[AC_HELP_STRING([--enable-zlib], [enable Stream Compression (XEP-0138) using zlib (default: yes)])],
|
||||
[case "${enableval}" in
|
||||
yes) zlib=true ;;
|
||||
no) zlib=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-zlib) ;;
|
||||
esac],[if test "x$zlib" = "x"; then zlib=true; fi])
|
||||
|
||||
AC_ARG_ENABLE(stun,
|
||||
[AC_HELP_STRING([--enable-stun], [enable STUN support (default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) stun=true ;;
|
||||
no) stun=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-stun) ;;
|
||||
esac],[if test "x$stun" = "x"; then stun=false; fi])
|
||||
|
||||
AC_ARG_ENABLE(riak,
|
||||
[AC_HELP_STRING([--enable-riak], [enable Riak support (default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) riak=true ;;
|
||||
no) riak=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-riak) ;;
|
||||
esac],[if test "x$riak" = "x"; then riak=false; fi])
|
||||
|
||||
AC_ARG_ENABLE(json,
|
||||
[AC_HELP_STRING([--enable-json], [enable JSON support for mod_bosh (default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) json=true ;;
|
||||
no) json=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-json) ;;
|
||||
esac],[if test "x$json" = "x"; then json=false; fi])
|
||||
|
||||
AC_ARG_ENABLE(iconv,
|
||||
[AC_HELP_STRING([--enable-iconv], [enable iconv support (default: yes)])],
|
||||
[case "${enableval}" in
|
||||
yes) iconv=true ;;
|
||||
no) iconv=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-iconv) ;;
|
||||
esac],[if test "x$iconv" = "x"; then iconv=true; fi])
|
||||
|
||||
AC_ARG_ENABLE(debug,
|
||||
[AC_HELP_STRING([--enable-debug], [enable debug information (default: yes)])],
|
||||
[case "${enableval}" in
|
||||
yes) debug=true ;;
|
||||
no) debug=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-debug) ;;
|
||||
esac],[if test "x$debug" = "x"; then debug=true; fi])
|
||||
|
||||
AC_ARG_ENABLE(pubsub_ng,
|
||||
[AC_HELP_STRING([--enable-pubsub-ng], [enable PubSub NG (default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) pubsub_ng=true ;;
|
||||
no) pubsub_ng=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-pubsub-ng) ;;
|
||||
esac],[if test "x$pubsub_ng" = "x"; then pubsub_ng=false; fi])
|
||||
|
||||
AC_ARG_ENABLE(http,
|
||||
[AC_HELP_STRING([--enable-http], [build external HTTP libraries ('ibrowse' and 'lhttpc', default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) http=true ;;
|
||||
no) http=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-http) ;;
|
||||
esac],[if test "x$http" = "x"; then http=false; fi])
|
||||
|
||||
AC_CONFIG_FILES([Makefile
|
||||
vars.config
|
||||
src/ejabberd.app.src])
|
||||
|
||||
ENABLEUSER=""
|
||||
AC_ARG_ENABLE(user,
|
||||
[AS_HELP_STRING([--enable-user[[[[=USER]]]]], [allow this system user to start ejabberd (default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) ENABLEUSER=`whoami` ;;
|
||||
no) ENABLEUSER="" ;;
|
||||
*) ENABLEUSER=$enableval
|
||||
esac],
|
||||
[])
|
||||
if test "$ENABLEUSER" != ""; then
|
||||
echo "allow this system user to start ejabberd: $ENABLEUSER"
|
||||
AC_SUBST([INSTALLUSER], [$ENABLEUSER])
|
||||
fi
|
||||
|
||||
AC_ERLANG_CHECK_LIB([sasl], [],
|
||||
[AC_MSG_ERROR([Erlang application 'sasl' was not found])])
|
||||
AC_ERLANG_CHECK_LIB([crypto], [],
|
||||
[AC_MSG_ERROR([Erlang application 'crypto' was not found])])
|
||||
AC_ERLANG_CHECK_LIB([public_key], [],
|
||||
[AC_MSG_ERROR([Erlang application 'public_key' was not found])])
|
||||
AC_ERLANG_CHECK_LIB([ssl], [],
|
||||
[AC_MSG_ERROR([Erlang application 'ssl' was not found])])
|
||||
AC_ERLANG_CHECK_LIB([mnesia], [],
|
||||
[AC_MSG_ERROR([Erlang application 'mnesia' was not found])])
|
||||
AC_ERLANG_CHECK_LIB([inets], [],
|
||||
[AC_MSG_ERROR([Erlang application 'inets' was not found])])
|
||||
AC_ERLANG_CHECK_LIB([odbc], [],
|
||||
[AC_MSG_ERROR([Erlang application 'odbc' was not found])])
|
||||
AC_ERLANG_CHECK_LIB([compiler], [],
|
||||
[AC_MSG_ERROR([Erlang application 'compiler' was not found])])
|
||||
if test "x$tools" = "xtrue"; then
|
||||
AC_ERLANG_CHECK_LIB([tools], [],
|
||||
[AC_MSG_ERROR([Erlang application 'tools' was not found])])
|
||||
AC_ERLANG_CHECK_LIB([runtime_tools], [],
|
||||
[AC_MSG_ERROR([Erlang application 'runtime_tools' was not found])])
|
||||
fi
|
||||
|
||||
AC_SUBST(hipe)
|
||||
AC_SUBST(roster_gateway_workaround)
|
||||
AC_SUBST(flash_hack)
|
||||
AC_SUBST(transient_supervisors)
|
||||
AC_SUBST(full_xml)
|
||||
AC_SUBST(nif)
|
||||
AC_SUBST(db_type)
|
||||
AC_SUBST(mysql)
|
||||
AC_SUBST(pgsql)
|
||||
AC_SUBST(pam)
|
||||
AC_SUBST(zlib)
|
||||
AC_SUBST(stun)
|
||||
AC_SUBST(riak)
|
||||
AC_SUBST(json)
|
||||
AC_SUBST(iconv)
|
||||
AC_SUBST(debug)
|
||||
AC_SUBST(pubsub_ng)
|
||||
AC_SUBST(http)
|
||||
AC_SUBST(tools)
|
||||
|
||||
AC_OUTPUT
|
||||
@@ -1,5 +0,0 @@
|
||||
% List of ejabberd-modules to add for ejabberd packaging (source archive and installer)
|
||||
%
|
||||
% HTTP-binding:
|
||||
%https://svn.process-one.net/ejabberd-modules/http_bind/trunk
|
||||
%https://svn.process-one.net/ejabberd-modules/mod_http_fileserver/trunk
|
||||
@@ -15,13 +15,13 @@ prepare_dirs ()
|
||||
ERL=`which erl`
|
||||
|
||||
EJA_SRC_DIR=$EJA_DIR/src/
|
||||
EJA_MSGS_DIR=$EJA_SRC_DIR/msgs/
|
||||
EJA_MSGS_DIR=$EJA_DIR/priv/msgs/
|
||||
EXTRACT_DIR=$EJA_DIR/contrib/extract_translations/
|
||||
EXTRACT_ERL=$EXTRACT_DIR/extract_translations.erl
|
||||
EXTRACT_BEAM=$EXTRACT_DIR/extract_translations.beam
|
||||
|
||||
SRC_DIR=$RUN_DIR/src
|
||||
MSGS_DIR=$SRC_DIR/msgs
|
||||
MSGS_DIR=$EJA_DIR/priv/msgs
|
||||
|
||||
if !([[ -n $EJA_DIR ]])
|
||||
then
|
||||
@@ -288,8 +288,8 @@ translation_instructions ()
|
||||
echo " $MSGS_PATH"
|
||||
}
|
||||
|
||||
EJA_DIR=`pwd`/..
|
||||
RUN_DIR=`pwd`/..
|
||||
EJA_DIR=`pwd`
|
||||
RUN_DIR=`pwd`
|
||||
PROJECT=ejabberd
|
||||
|
||||
while [ $# -ne 0 ] ; do
|
||||
|
||||
+15
-2
@@ -21,10 +21,11 @@ release:
|
||||
@echo "\newcommand{\version}{"`sed '/vsn/!d;s/\(.*\)"\(.*\)"\(.*\)/\2/' ../src/ejabberd.app`"}" >> version.tex
|
||||
@echo -n "% Contributed modules (automatically generated)." > contributed_modules.tex
|
||||
@echo -e "$(CONTRIBUTED_MODULES)" >> contributed_modules.tex
|
||||
@echo "% mod_admin_p1 commands list."
|
||||
|
||||
html: guide.html dev.html features.html
|
||||
html: guide.html dev.html features.html commercial.html
|
||||
|
||||
pdf: guide.pdf features.pdf
|
||||
pdf: guide.pdf features.pdf commercial.pdf
|
||||
|
||||
clean:
|
||||
rm -f *.aux
|
||||
@@ -60,3 +61,15 @@ guide.pdf: guide.tex
|
||||
|
||||
features.pdf: features.tex
|
||||
pdflatex features.tex
|
||||
|
||||
commercial.html: commercial.tex
|
||||
./mod_admin_p1_commands.sh
|
||||
hevea -fix -pedantic commercial.tex
|
||||
|
||||
commercial.pdf: commercial.tex
|
||||
./mod_admin_p1_commands.sh
|
||||
pdflatex commercial.tex
|
||||
pdflatex commercial.tex
|
||||
pdflatex commercial.tex
|
||||
makeindex commercial.idx
|
||||
pdflatex commercial.tex
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@author Mickael Remond <mickael.remond@process-one.net>
|
||||
[http://www.process-one.net/]
|
||||
@copyright 2013 ProcessOne
|
||||
@copyright 2012 ProcessOne
|
||||
@version {@vsn}, {@date} {@time}
|
||||
@title ejabberd Development API Documentation
|
||||
|
||||
|
||||
+6184
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -2,7 +2,7 @@
|
||||
"http://www.w3.org/TR/REC-html40/loose.dtd">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Ejabberd 2.1.12 Developers Guide
|
||||
<TITLE>Ejabberd 2.1.11 Developers Guide
|
||||
</TITLE>
|
||||
|
||||
<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
|
||||
@@ -49,7 +49,7 @@ TD P{margin:0px;}
|
||||
<!--HEVEA command line is: /usr/bin/hevea -fix -pedantic dev.tex -->
|
||||
<!--CUT DEF section 1 --><P><A NAME="titlepage"></A>
|
||||
|
||||
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.12 Developers Guide</H1><H3 CLASS="titlerest">Alexey Shchepin<BR>
|
||||
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.11 Developers Guide</H1><H3 CLASS="titlerest">Alexey Shchepin<BR>
|
||||
<A HREF="mailto:alexey@sevcom.net"><TT>mailto:alexey@sevcom.net</TT></A><BR>
|
||||
<A HREF="xmpp:aleksey@jabber.ru"><TT>xmpp:aleksey@jabber.ru</TT></A></H3></TD></TR>
|
||||
</TABLE><DIV CLASS="center">
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
"http://www.w3.org/TR/REC-html40/loose.dtd">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Ejabberd 2.1.12 Feature Sheet
|
||||
<TITLE>Ejabberd 2.1.11 Feature Sheet
|
||||
</TITLE>
|
||||
|
||||
<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
|
||||
@@ -50,7 +50,7 @@ SPAN{width:20%; float:right; text-align:left; margin-left:auto;}
|
||||
<!--HEVEA command line is: /usr/bin/hevea -fix -pedantic features.tex -->
|
||||
<!--CUT DEF section 1 --><P><A NAME="titlepage"></A>
|
||||
|
||||
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.12 Feature Sheet</H1><H3 CLASS="titlerest">Sander Devrieze<BR>
|
||||
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.11 Feature Sheet</H1><H3 CLASS="titlerest">Sander Devrieze<BR>
|
||||
<A HREF="mailto:s.devrieze@pandora.be"><TT>mailto:s.devrieze@pandora.be</TT></A><BR>
|
||||
<A HREF="xmpp:sander@devrieze.dyndns.org"><TT>xmpp:sander@devrieze.dyndns.org</TT></A></H3></TD></TR>
|
||||
</TABLE><DIV CLASS="center">
|
||||
|
||||
+83
-90
@@ -6,7 +6,7 @@
|
||||
|
||||
|
||||
|
||||
ejabberd 2.1.12
|
||||
ejabberd 2.1.11
|
||||
|
||||
Installation and Operation Guide
|
||||
|
||||
@@ -76,7 +76,7 @@ BLOCKQUOTE.figure DIV.center DIV.center HR{display:none;}
|
||||
<HR SIZE=2><BR>
|
||||
<BR>
|
||||
|
||||
<TABLE CELLSPACING=6 CELLPADDING=0><TR><TD ALIGN=right NOWRAP> <FONT SIZE=6><B>ejabberd 2.1.12 </B></FONT></TD></TR>
|
||||
<TABLE CELLSPACING=6 CELLPADDING=0><TR><TD ALIGN=right NOWRAP> <FONT SIZE=6><B>ejabberd 2.1.11 </B></FONT></TD></TR>
|
||||
<TR><TD ALIGN=right NOWRAP> </TD></TR>
|
||||
<TR><TD ALIGN=right NOWRAP> <FONT SIZE=6>Installation and Operation Guide</FONT></TD></TR>
|
||||
</TABLE><BR>
|
||||
@@ -1068,7 +1068,7 @@ then this option is not respected, and the action performed is <TT>closeold</TT>
|
||||
of the machine, in case it isn’t detected automatically.
|
||||
The FQDN is used to authenticate some clients that use the DIGEST-MD5 SASL mechanism.
|
||||
The option syntax is:
|
||||
</P><DL CLASS="description"><DT CLASS="dt-description"><B><TT>{fqdn, undefined|FqdnString|[FqdnString]}.</TT></B></DT></DL><P> <A NAME="internalauth"></A> </P><!--TOC subsubsection Internal-->
|
||||
</P><DL CLASS="description"><DT CLASS="dt-description"><B><TT>{fqdn, undefined|FqdnString}.</TT></B></DT></DL><P> <A NAME="internalauth"></A> </P><!--TOC subsubsection Internal-->
|
||||
<H4 CLASS="subsubsection"><!--SEC ANCHOR --><A HREF="#internalauth">Internal</A></H4><!--SEC END --><P> <A NAME="internalauth"></A>
|
||||
</P><P><TT>ejabberd</TT> uses its internal Mnesia database as the default authentication method.
|
||||
The value <TT>internal</TT> will enable the internal authentication method.</P><P>The option <TT>{auth_password_format, plain|scram}</TT>
|
||||
@@ -1115,7 +1115,7 @@ the CacheTimeInteger indicates the number of seconds that ejabberd can reuse
|
||||
the authentication information since the user last disconnected,
|
||||
to verify again the user authentication without querying again the extauth script.
|
||||
Note: caching should not be enabled in a host if internal auth is also enabled.
|
||||
If caching is enabled, <TT>mod_last</TT> must be enabled also in that vhost.
|
||||
If caching is enabled, <TT>mod_last</TT> or <TT>mod_last_odbc</TT> must be enabled also in that vhost.
|
||||
</DD></DL><P>This example sets external authentication, the extauth script, enables caching for 10 minutes,
|
||||
and starts three instances of the script for each virtual host defined in ejabberd:
|
||||
</P><PRE CLASS="verbatim">{auth_method, [external]}.
|
||||
@@ -1569,10 +1569,12 @@ MySQL interface. Anyway, the first configuration step is to define the odbc
|
||||
</PRE><P> <A NAME="mysqlstorage"></A> </P><!--TOC subsubsection Storage-->
|
||||
<H4 CLASS="subsubsection"><!--SEC ANCHOR --><A HREF="#mysqlstorage">Storage</A></H4><!--SEC END --><P> <A NAME="mysqlstorage"></A>
|
||||
</P><P>MySQL also can be used to store information into from several <TT>ejabberd</TT>
|
||||
modules. See section <A HREF="#modoverview">3.3.1</A> to see which modules can be used with
|
||||
modules. See section <A HREF="#modoverview">3.3.1</A> to see which modules have a version
|
||||
with the ‘_odbc’. This suffix indicates that the module can be used with
|
||||
relational databases like MySQL. To enable storage to your database, just make
|
||||
sure that your database is running well (see previous sections), and add the
|
||||
module option <TT>{db_type, odbc}</TT>.</P><P> <A NAME="mssql"></A> </P><!--TOC subsection Microsoft SQL Server-->
|
||||
sure that your database is running well (see previous sections), and replace the
|
||||
suffix-less or ldap module variant with the odbc module variant. Keep in mind
|
||||
that you cannot have several variants of the same module loaded!</P><P> <A NAME="mssql"></A> </P><!--TOC subsection Microsoft SQL Server-->
|
||||
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc34">3.2.2</A>  <A HREF="#mssql">Microsoft SQL Server</A></H3><!--SEC END --><P> <A NAME="mssql"></A>
|
||||
</P><P>Although this section will describe <TT>ejabberd</TT>’s configuration when you want to
|
||||
use Microsoft SQL Server, it does not describe Microsoft SQL Server’s
|
||||
@@ -1599,10 +1601,13 @@ is the same as the configuration for
|
||||
ODBC compatible servers (see section <A HREF="#odbcauth">3.2.4</A>).</P><P> <A NAME="mssqlstorage"></A> </P><!--TOC subsubsection Storage-->
|
||||
<H4 CLASS="subsubsection"><!--SEC ANCHOR --><A HREF="#mssqlstorage">Storage</A></H4><!--SEC END --><P> <A NAME="mssqlstorage"></A>
|
||||
</P><P>Microsoft SQL Server also can be used to store information into from several
|
||||
modules. See section <A HREF="#modoverview">3.3.1</A> to see which modules can be used with
|
||||
relational databases like MySQL. To enable storage to your database, just make
|
||||
sure that your database is running well (see previous sections), and add the
|
||||
module option <TT>{db_type, odbc}</TT>.</P><P> <A NAME="pgsql"></A> </P><!--TOC subsection PostgreSQL-->
|
||||
<TT>ejabberd</TT> modules. See section <A HREF="#modoverview">3.3.1</A> to see which modules have
|
||||
a version with the ‘_odbc’. This suffix indicates that the module can be used
|
||||
with relational databases like Microsoft SQL Server. To enable storage to your
|
||||
database, just make sure that your database is running well (see previous
|
||||
sections), and replace the suffix-less or ldap module variant with the odbc
|
||||
module variant. Keep in mind that you cannot have several variants of the same
|
||||
module loaded!</P><P> <A NAME="pgsql"></A> </P><!--TOC subsection PostgreSQL-->
|
||||
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc35">3.2.3</A>  <A HREF="#pgsql">PostgreSQL</A></H3><!--SEC END --><P> <A NAME="pgsql"></A>
|
||||
</P><P>Although this section will describe <TT>ejabberd</TT>’s configuration when you want to
|
||||
use the native PostgreSQL driver, it does not describe PostgreSQL’s installation
|
||||
@@ -1654,10 +1659,12 @@ PostgreSQL interface. Anyway, the first configuration step is to define the odbc
|
||||
</PRE><P> <A NAME="pgsqlstorage"></A> </P><!--TOC subsubsection Storage-->
|
||||
<H4 CLASS="subsubsection"><!--SEC ANCHOR --><A HREF="#pgsqlstorage">Storage</A></H4><!--SEC END --><P> <A NAME="pgsqlstorage"></A>
|
||||
</P><P>PostgreSQL also can be used to store information into from several <TT>ejabberd</TT>
|
||||
modules. See section <A HREF="#modoverview">3.3.1</A> to see which modules can be used with
|
||||
relational databases like MySQL. To enable storage to your database, just make
|
||||
sure that your database is running well (see previous sections), and add the
|
||||
module option <TT>{db_type, odbc}</TT>.</P><P> <A NAME="odbc"></A> </P><!--TOC subsection ODBC Compatible-->
|
||||
modules. See section <A HREF="#modoverview">3.3.1</A> to see which modules have a version
|
||||
with the ‘_odbc’. This suffix indicates that the module can be used with
|
||||
relational databases like PostgreSQL. To enable storage to your database, just
|
||||
make sure that your database is running well (see previous sections), and
|
||||
replace the suffix-less or ldap module variant with the odbc module variant.
|
||||
Keep in mind that you cannot have several variants of the same module loaded!</P><P> <A NAME="odbc"></A> </P><!--TOC subsection ODBC Compatible-->
|
||||
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc36">3.2.4</A>  <A HREF="#odbc">ODBC Compatible</A></H3><!--SEC END --><P> <A NAME="odbc"></A>
|
||||
</P><P>Although this section will describe <TT>ejabberd</TT>’s configuration when you want to
|
||||
use the ODBC driver, it does not describe the installation and database creation
|
||||
@@ -1696,11 +1703,13 @@ example:
|
||||
</PRE><P> <A NAME="odbcstorage"></A> </P><!--TOC subsubsection Storage-->
|
||||
<H4 CLASS="subsubsection"><!--SEC ANCHOR --><A HREF="#odbcstorage">Storage</A></H4><!--SEC END --><P> <A NAME="odbcstorage"></A>
|
||||
</P><P>An ODBC compatible database also can be used to store information into from
|
||||
several <TT>ejabberd</TT>
|
||||
modules. See section <A HREF="#modoverview">3.3.1</A> to see which modules can be used with
|
||||
relational databases like MySQL. To enable storage to your database, just make
|
||||
sure that your database is running well (see previous sections), and add the
|
||||
module option <TT>{db_type, odbc}</TT>.</P><P> <A NAME="ldap"></A> </P><!--TOC subsection LDAP-->
|
||||
several <TT>ejabberd</TT> modules. See section <A HREF="#modoverview">3.3.1</A> to see which
|
||||
modules have a version with the ‘_odbc’. This suffix indicates that the module
|
||||
can be used with ODBC compatible relational databases. To enable storage to your
|
||||
database, just make sure that your database is running well (see previous
|
||||
sections), and replace the suffix-less or ldap module variant with the odbc
|
||||
module variant. Keep in mind that you cannot have several variants of the same
|
||||
module loaded!</P><P> <A NAME="ldap"></A> </P><!--TOC subsection LDAP-->
|
||||
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc37">3.2.5</A>  <A HREF="#ldap">LDAP</A></H3><!--SEC END --><P> <A NAME="ldap"></A>
|
||||
</P><P><TT>ejabberd</TT> has built-in LDAP support. You can authenticate users against LDAP
|
||||
server and use LDAP directory as vCard storage.</P><P>Usually <TT>ejabberd</TT> treats LDAP as a read-only storage:
|
||||
@@ -1950,7 +1959,10 @@ all entries end with a comma:
|
||||
<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=1><TR><TD ALIGN=left NOWRAP><B>Module</B></TD><TD ALIGN=left NOWRAP><B>Feature</B></TD><TD ALIGN=left NOWRAP><B>Dependencies</B></TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><TT>mod_adhoc</TT></TD><TD ALIGN=left NOWRAP>Ad-Hoc Commands (<A HREF="http://xmpp.org/extensions/xep-0050.html">XEP-0050</A>)</TD><TD ALIGN=left NOWRAP> </TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modannounce"><TT>mod_announce</TT></A></TD><TD ALIGN=left NOWRAP>Manage announcements</TD><TD ALIGN=left NOWRAP>recommends <TT>mod_adhoc</TT></TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modannounce"><TT>mod_announce_odbc</TT></A></TD><TD ALIGN=left NOWRAP>Manage announcements</TD><TD ALIGN=left NOWRAP>recommends <TT>mod_adhoc</TT></TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP> </TD><TD ALIGN=left NOWRAP> </TD><TD ALIGN=left NOWRAP>supported DB (*)</TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><TT>mod_blocking</TT></TD><TD ALIGN=left NOWRAP>Simple Communications Blocking (<A HREF="http://xmpp.org/extensions/xep-0191.html">XEP-0191</A>)</TD><TD ALIGN=left NOWRAP><TT>mod_privacy</TT></TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><TT>mod_blocking_odbc</TT></TD><TD ALIGN=left NOWRAP>Simple Communications Blocking (<A HREF="http://xmpp.org/extensions/xep-0191.html">XEP-0191</A>)</TD><TD ALIGN=left NOWRAP><TT>mod_privacy_odbc</TT></TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><TT>mod_caps</TT></TD><TD ALIGN=left NOWRAP>Entity Capabilities (<A HREF="http://xmpp.org/extensions/xep-0115.html">XEP-0115</A>)</TD><TD ALIGN=left NOWRAP> </TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><TT>mod_configure</TT></TD><TD ALIGN=left NOWRAP>Server configuration using Ad-Hoc</TD><TD ALIGN=left NOWRAP><TT>mod_adhoc</TT></TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#moddisco"><TT>mod_disco</TT></A></TD><TD ALIGN=left NOWRAP>Service Discovery (<A HREF="http://xmpp.org/extensions/xep-0030.html">XEP-0030</A>)</TD><TD ALIGN=left NOWRAP> </TD></TR>
|
||||
@@ -1958,38 +1970,73 @@ all entries end with a comma:
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modhttpbind"><TT>mod_http_bind</TT></A></TD><TD ALIGN=left NOWRAP>XMPP over Bosh service (HTTP Binding)</TD><TD ALIGN=left NOWRAP> </TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modhttpfileserver"><TT>mod_http_fileserver</TT></A></TD><TD ALIGN=left NOWRAP>Small HTTP file server</TD><TD ALIGN=left NOWRAP> </TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modirc"><TT>mod_irc</TT></A></TD><TD ALIGN=left NOWRAP>IRC transport</TD><TD ALIGN=left NOWRAP> </TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modirc"><TT>mod_irc_odbc</TT></A></TD><TD ALIGN=left NOWRAP>IRC transport</TD><TD ALIGN=left NOWRAP>supported DB (*)</TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modlast"><TT>mod_last</TT></A></TD><TD ALIGN=left NOWRAP>Last Activity (<A HREF="http://xmpp.org/extensions/xep-0012.html">XEP-0012</A>)</TD><TD ALIGN=left NOWRAP> </TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modlast"><TT>mod_last_odbc</TT></A></TD><TD ALIGN=left NOWRAP>Last Activity (<A HREF="http://xmpp.org/extensions/xep-0012.html">XEP-0012</A>)</TD><TD ALIGN=left NOWRAP>supported DB (*)</TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modmuc"><TT>mod_muc</TT></A></TD><TD ALIGN=left NOWRAP>Multi-User Chat (<A HREF="http://xmpp.org/extensions/xep-0045.html">XEP-0045</A>)</TD><TD ALIGN=left NOWRAP> </TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modmuclog"><TT>mod_muc_log</TT></A></TD><TD ALIGN=left NOWRAP>Multi-User Chat room logging</TD><TD ALIGN=left NOWRAP><TT>mod_muc</TT></TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modmuc"><TT>mod_muc_odbc</TT></A></TD><TD ALIGN=left NOWRAP>Multi-User Chat (<A HREF="http://xmpp.org/extensions/xep-0045.html">XEP-0045</A>)</TD><TD ALIGN=left NOWRAP>supported DB (*)</TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modmuclog"><TT>mod_muc_log</TT></A></TD><TD ALIGN=left NOWRAP>Multi-User Chat room logging</TD><TD ALIGN=left NOWRAP><TT>mod_muc</TT> or <TT>mod_muc_odbc</TT></TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modoffline"><TT>mod_offline</TT></A></TD><TD ALIGN=left NOWRAP>Offline message storage (<A HREF="http://xmpp.org/extensions/xep-0160.html">XEP-0160</A>)</TD><TD ALIGN=left NOWRAP> </TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modoffline"><TT>mod_offline_odbc</TT></A></TD><TD ALIGN=left NOWRAP>Offline message storage (<A HREF="http://xmpp.org/extensions/xep-0160.html">XEP-0160</A>)</TD><TD ALIGN=left NOWRAP>supported DB (*)</TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modping"><TT>mod_ping</TT></A></TD><TD ALIGN=left NOWRAP>XMPP Ping and periodic keepalives (<A HREF="http://xmpp.org/extensions/xep-0199.html">XEP-0199</A>)</TD><TD ALIGN=left NOWRAP> </TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modprescounter"><TT>mod_pres_counter</TT></A></TD><TD ALIGN=left NOWRAP>Detect presence subscription flood</TD><TD ALIGN=left NOWRAP> </TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modprivacy"><TT>mod_privacy</TT></A></TD><TD ALIGN=left NOWRAP>Blocking Communication (<A HREF="http://xmpp.org/extensions/xep-0016.html">XEP-0016</A>)</TD><TD ALIGN=left NOWRAP> </TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modprivacy"><TT>mod_privacy_odbc</TT></A></TD><TD ALIGN=left NOWRAP>Blocking Communication (<A HREF="http://xmpp.org/extensions/xep-0016.html">XEP-0016</A>)</TD><TD ALIGN=left NOWRAP>supported DB (*)</TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modprivate"><TT>mod_private</TT></A></TD><TD ALIGN=left NOWRAP>Private XML Storage (<A HREF="http://xmpp.org/extensions/xep-0049.html">XEP-0049</A>)</TD><TD ALIGN=left NOWRAP> </TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modprivate"><TT>mod_private_odbc</TT></A></TD><TD ALIGN=left NOWRAP>Private XML Storage (<A HREF="http://xmpp.org/extensions/xep-0049.html">XEP-0049</A>)</TD><TD ALIGN=left NOWRAP>supported DB (*)</TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modproxy"><TT>mod_proxy65</TT></A></TD><TD ALIGN=left NOWRAP>SOCKS5 Bytestreams (<A HREF="http://xmpp.org/extensions/xep-0065.html">XEP-0065</A>)</TD><TD ALIGN=left NOWRAP> </TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modpubsub"><TT>mod_pubsub</TT></A></TD><TD ALIGN=left NOWRAP>Pub-Sub (<A HREF="http://xmpp.org/extensions/xep-0060.html">XEP-0060</A>), PEP (<A HREF="http://xmpp.org/extensions/xep-0163.html">XEP-0163</A>)</TD><TD ALIGN=left NOWRAP><TT>mod_caps</TT></TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modpubsub"><TT>mod_pubsub_odbc</TT></A></TD><TD ALIGN=left NOWRAP>Pub-Sub (<A HREF="http://xmpp.org/extensions/xep-0060.html">XEP-0060</A>), PEP (<A HREF="http://xmpp.org/extensions/xep-0163.html">XEP-0163</A>)</TD><TD ALIGN=left NOWRAP>supported DB (*) and <TT>mod_caps</TT></TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modregister"><TT>mod_register</TT></A></TD><TD ALIGN=left NOWRAP>In-Band Registration (<A HREF="http://xmpp.org/extensions/xep-0077.html">XEP-0077</A>)</TD><TD ALIGN=left NOWRAP> </TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modregisterweb"><TT>mod_register_web</TT></A></TD><TD ALIGN=left NOWRAP>Web for Account Registrations</TD><TD ALIGN=left NOWRAP> </TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modroster"><TT>mod_roster</TT></A></TD><TD ALIGN=left NOWRAP>Roster management (XMPP IM)</TD><TD ALIGN=left NOWRAP> </TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modroster"><TT>mod_roster_odbc</TT></A></TD><TD ALIGN=left NOWRAP>Roster management (XMPP IM)</TD><TD ALIGN=left NOWRAP>supported DB (*)</TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modservicelog"><TT>mod_service_log</TT></A></TD><TD ALIGN=left NOWRAP>Copy user messages to logger service</TD><TD ALIGN=left NOWRAP> </TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modsharedroster"><TT>mod_shared_roster</TT></A></TD><TD ALIGN=left NOWRAP>Shared roster management</TD><TD ALIGN=left NOWRAP><TT>mod_roster</TT></TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modsharedrosterldap"><TT>mod_shared_roster_ldap</TT></A></TD><TD ALIGN=left NOWRAP>LDAP Shared roster management</TD><TD ALIGN=left NOWRAP><TT>mod_roster</TT></TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modsharedroster"><TT>mod_shared_roster</TT></A></TD><TD ALIGN=left NOWRAP>Shared roster management</TD><TD ALIGN=left NOWRAP><TT>mod_roster</TT> or</TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP> </TD><TD ALIGN=left NOWRAP> </TD><TD ALIGN=left NOWRAP><TT>mod_roster_odbc</TT></TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modsharedroster"><TT>mod_shared_roster_odbc</TT></A></TD><TD ALIGN=left NOWRAP>Shared roster management</TD><TD ALIGN=left NOWRAP>supported DB (*) and</TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP> </TD><TD ALIGN=left NOWRAP> </TD><TD ALIGN=left NOWRAP><TT>mod_roster</TT> or <TT>mod_roster_odbc</TT></TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modsharedrosterldap"><TT>mod_shared_roster_ldap</TT></A></TD><TD ALIGN=left NOWRAP>LDAP Shared roster management</TD><TD ALIGN=left NOWRAP><TT>mod_roster</TT> or</TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP> </TD><TD ALIGN=left NOWRAP> </TD><TD ALIGN=left NOWRAP><TT>mod_roster_odbc</TT></TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modsic"><TT>mod_sic</TT></A></TD><TD ALIGN=left NOWRAP>Server IP Check (<A HREF="http://xmpp.org/extensions/xep-0279.html">XEP-0279</A>)</TD><TD ALIGN=left NOWRAP> </TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modstats"><TT>mod_stats</TT></A></TD><TD ALIGN=left NOWRAP>Statistics Gathering (<A HREF="http://xmpp.org/extensions/xep-0039.html">XEP-0039</A>)</TD><TD ALIGN=left NOWRAP> </TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modtime"><TT>mod_time</TT></A></TD><TD ALIGN=left NOWRAP>Entity Time (<A HREF="http://xmpp.org/extensions/xep-0202.html">XEP-0202</A>)</TD><TD ALIGN=left NOWRAP> </TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modvcard"><TT>mod_vcard</TT></A></TD><TD ALIGN=left NOWRAP>vcard-temp (<A HREF="http://xmpp.org/extensions/xep-0054.html">XEP-0054</A>)</TD><TD ALIGN=left NOWRAP> </TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modvcardldap"><TT>mod_vcard_ldap</TT></A></TD><TD ALIGN=left NOWRAP>vcard-temp (<A HREF="http://xmpp.org/extensions/xep-0054.html">XEP-0054</A>)</TD><TD ALIGN=left NOWRAP>LDAP server</TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modvcardxupdate"><TT>mod_vcard_xupdate</TT></A></TD><TD ALIGN=left NOWRAP>vCard-Based Avatars (<A HREF="http://xmpp.org/extensions/xep-0153.html">XEP-0153</A>)</TD><TD ALIGN=left NOWRAP><TT>mod_vcard</TT></TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modvcard"><TT>mod_vcard_odbc</TT></A></TD><TD ALIGN=left NOWRAP>vcard-temp (<A HREF="http://xmpp.org/extensions/xep-0054.html">XEP-0054</A>)</TD><TD ALIGN=left NOWRAP>supported DB (*)</TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modvcardxupdate"><TT>mod_vcard_xupdate</TT></A></TD><TD ALIGN=left NOWRAP>vCard-Based Avatars (<A HREF="http://xmpp.org/extensions/xep-0153.html">XEP-0153</A>)</TD><TD ALIGN=left NOWRAP><TT>mod_vcard</TT> or <TT>mod_vcard_odbc</TT></TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modvcardxupdate"><TT>mod_vcard_xupdate_odbc</TT></A></TD><TD ALIGN=left NOWRAP>vCard-Based Avatars (<A HREF="http://xmpp.org/extensions/xep-0153.html">XEP-0153</A>)</TD><TD ALIGN=left NOWRAP><TT>mod_vcard</TT> or <TT>mod_vcard_odbc</TT></TD></TR>
|
||||
<TR><TD ALIGN=left NOWRAP><A HREF="#modversion"><TT>mod_version</TT></A></TD><TD ALIGN=left NOWRAP>Software Version (<A HREF="http://xmpp.org/extensions/xep-0092.html">XEP-0092</A>)</TD><TD ALIGN=left NOWRAP> </TD></TR>
|
||||
</TABLE>
|
||||
<DIV CLASS="center"><HR WIDTH="80%" SIZE=2></DIV></DIV></BLOCKQUOTE><UL CLASS="itemize"><LI CLASS="li-itemize">
|
||||
(*) This module requires a supported database. For a list of supported databases, see section <A HREF="#database">3.2</A>.
|
||||
</LI></UL><P>You can see which database backend each module needs by looking at the suffix:
|
||||
</P><UL CLASS="itemize"><LI CLASS="li-itemize">
|
||||
No suffix, this means that the module uses Erlang’s built-in database
|
||||
Mnesia as backend, or a ODBC database in some cases (see <A HREF="#database">3.2</A>).
|
||||
No suffix, this means that the modules uses Erlang’s built-in database
|
||||
Mnesia as backend.
|
||||
</LI><LI CLASS="li-itemize">‘_odbc’, this means that the module needs a supported database
|
||||
(see <A HREF="#database">3.2</A>) as backend.
|
||||
</LI><LI CLASS="li-itemize">‘_ldap’, this means that the module needs an LDAP server as backend.
|
||||
</LI></UL><P>If you want to,
|
||||
it is possible to use a relational database to store the tables created by some ejabberd modules.
|
||||
You can do this by changing the module name to a name with an
|
||||
<TT>_odbc</TT> suffix in <TT>ejabberd</TT> config file. You can use a relational
|
||||
database for the following data:</P><UL CLASS="itemize"><LI CLASS="li-itemize">
|
||||
Last connection date and time: Use <TT>mod_last_odbc</TT> instead of
|
||||
<TT>mod_last</TT>.
|
||||
</LI><LI CLASS="li-itemize">Offline messages: Use <TT>mod_offline_odbc</TT> instead of
|
||||
<TT>mod_offline</TT>.
|
||||
</LI><LI CLASS="li-itemize">Rosters: Use <TT>mod_roster_odbc</TT> instead of <TT>mod_roster</TT>.
|
||||
</LI><LI CLASS="li-itemize">Shared Rosters: Use <TT>mod_shared_roster_odbc</TT> instead of <TT>mod_shared_roster</TT>.
|
||||
</LI><LI CLASS="li-itemize">Users’ VCARD: Use <TT>mod_vcard_odbc</TT> instead of <TT>mod_vcard</TT>.
|
||||
</LI><LI CLASS="li-itemize">vCard-Based Avatars: Use <TT>mod_vcard_xupdate_odbc</TT> instead of <TT>mod_vcard_xupdate</TT>.
|
||||
</LI><LI CLASS="li-itemize">Private XML storage: Use <TT>mod_private_odbc</TT> instead of <TT>mod_private</TT>.
|
||||
</LI><LI CLASS="li-itemize">User rules for blocking communications: Use <TT>mod_privacy_odbc</TT> instead of <TT>mod_privacy</TT>.
|
||||
</LI><LI CLASS="li-itemize">Simple Communications Blocking: Use <TT>mod_blocking_odbc</TT> instead of <TT>mod_blocking</TT>.
|
||||
</LI><LI CLASS="li-itemize">Pub-Sub nodes, items and subscriptions: Use <TT>mod_pubsub_odbc</TT> instead of <TT>mod_pubsub</TT>.
|
||||
</LI><LI CLASS="li-itemize">Multi-user chats: Use <TT>mod_muc_odbc</TT> instead of <TT>mod_muc</TT>.
|
||||
</LI><LI CLASS="li-itemize">Manage announcements: Use <TT>mod_announce_odbc</TT> instead of <TT>mod_announce</TT>.
|
||||
</LI><LI CLASS="li-itemize">IRC transport: Use <TT>mod_irc_odbc</TT> instead of <TT>mod_irc</TT>.
|
||||
</LI></UL><P>You can find more
|
||||
<A HREF="http://www.ejabberd.im/contributions">contributed modules</A> on the
|
||||
<TT>ejabberd</TT> website. Please remember that these contributions might not work or
|
||||
@@ -2081,11 +2128,7 @@ login. The message is <EM>not sent</EM> to any currently connected user.
|
||||
Any message sent to this JID removes the existing message of the day (MOTD).
|
||||
</DD></DL><P>Options:
|
||||
</P><DL CLASS="description"><DT CLASS="dt-description">
|
||||
<B><TT>{db_type, mnesia|odbc}</TT></B></DT><DD CLASS="dd-description">
|
||||
Define the type of storage where the module will create the tables and store user information.
|
||||
The default is to store in the internal Mnesia database.
|
||||
If <TT>odbc</TT> value is defined, make sure you have defined the database, see <A HREF="#database">3.2</A>.
|
||||
</DD><DT CLASS="dt-description"><B><TT>{access, AccessName}</TT></B></DT><DD CLASS="dd-description"> This option specifies who is allowed to
|
||||
<B><TT>{access, AccessName}</TT></B></DT><DD CLASS="dd-description"> This option specifies who is allowed to
|
||||
send announcements and to set the message of the day (by default, nobody is
|
||||
able to send such messages).
|
||||
</DD></DL><P>Examples:
|
||||
@@ -2361,10 +2404,6 @@ service. If the <TT>host</TT> option is not specified, the Jabber ID will be the
|
||||
hostname of the virtual host with the prefix ‘<TT>irc.</TT>’. The keyword "@HOST@"
|
||||
is replaced at start time with the real virtual host name.
|
||||
|
||||
</DD><DT CLASS="dt-description"><B><TT>{db_type, mnesia|odbc}</TT></B></DT><DD CLASS="dd-description">
|
||||
Define the type of storage where the module will create the tables and store user information.
|
||||
The default is to store in the internal Mnesia database.
|
||||
If <TT>odbc</TT> value is defined, make sure you have defined the database, see <A HREF="#database">3.2</A>.
|
||||
</DD><DT CLASS="dt-description"><B><TT>{access, AccessName}</TT></B></DT><DD CLASS="dd-description"> This option can be used to specify who
|
||||
may use the IRC transport (default value: <TT>all</TT>).
|
||||
</DD><DT CLASS="dt-description"><B><TT>{default_encoding, Encoding}</TT></B></DT><DD CLASS="dd-description"> Set the default IRC encoding.
|
||||
@@ -2405,10 +2444,6 @@ connected user was last active on the server, or to query the uptime of the
|
||||
</P><DL CLASS="description"><DT CLASS="dt-description">
|
||||
<B><TT>{iqdisc, Discipline}</TT></B></DT><DD CLASS="dd-description"> This specifies
|
||||
the processing discipline for Last activity (<TT>jabber:iq:last</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>).
|
||||
</DD><DT CLASS="dt-description"><B><TT>{db_type, mnesia|odbc}</TT></B></DT><DD CLASS="dd-description">
|
||||
Define the type of storage where the module will create the tables and store user information.
|
||||
The default is to store in the internal Mnesia database.
|
||||
If <TT>odbc</TT> value is defined, make sure you have defined the database, see <A HREF="#database">3.2</A>.
|
||||
</DD></DL><P> <A NAME="modmuc"></A> </P><!--TOC subsection <TT>mod_muc</TT>-->
|
||||
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc48">3.3.10</A>  <A HREF="#modmuc"><TT>mod_muc</TT></A></H3><!--SEC END --><P> <A NAME="modmuc"></A>
|
||||
</P><P>This module provides a Multi-User Chat (<A HREF="http://xmpp.org/extensions/xep-0045.html">XEP-0045</A>) service.
|
||||
@@ -2437,10 +2472,6 @@ service. If the <TT>host</TT> option is not specified, the Jabber ID will be the
|
||||
hostname of the virtual host with the prefix ‘<TT>conference.</TT>’. The keyword "@HOST@"
|
||||
is replaced at start time with the real virtual host name.
|
||||
|
||||
</DD><DT CLASS="dt-description"><B><TT>{db_type, mnesia|odbc}</TT></B></DT><DD CLASS="dd-description">
|
||||
Define the type of storage where the module will create the tables and store user information.
|
||||
The default is to store in the internal Mnesia database.
|
||||
If <TT>odbc</TT> value is defined, make sure you have defined the database, see <A HREF="#database">3.2</A>.
|
||||
</DD><DT CLASS="dt-description"><B><TT>{access, AccessName}</TT></B></DT><DD CLASS="dd-description"> You can specify who is allowed to use
|
||||
the Multi-User Chat service. By default everyone is allowed to use it.
|
||||
</DD><DT CLASS="dt-description"><B><TT>{access_create, AccessName}</TT></B></DT><DD CLASS="dd-description"> To configure who is
|
||||
@@ -2694,10 +2725,6 @@ Define the format of the log files:
|
||||
<TT>html</TT> stores in HTML format,
|
||||
<TT>plaintext</TT> stores in plain text.
|
||||
The default value is <TT>html</TT>.
|
||||
</DD><DT CLASS="dt-description"><B><TT>{file_permissions, {Mode, Group}}</TT></B></DT><DD CLASS="dd-description">
|
||||
Define the permissions that must be used when creating the log files:
|
||||
the number of the mode, and the numeric id of the group that will own the files.
|
||||
The default value is <TT>{644, 33}</TT>.
|
||||
</DD><DT CLASS="dt-description"><B><TT>{outdir, Path}</TT></B></DT><DD CLASS="dd-description">
|
||||
This option sets the full path to the directory in which the HTML files should
|
||||
be stored. Make sure the <TT>ejabberd</TT> daemon user has write access on that
|
||||
@@ -2759,8 +2786,6 @@ top link will be the default <CODE><a href="/">Home</a></CODE>.
|
||||
{access_log, muc_log},
|
||||
{cssfile, false},
|
||||
{dirtype, subdirs},
|
||||
{dirtype, subdirs},
|
||||
{file_permissions, {644, 33}},
|
||||
{outdir, "/var/www/muclogs"},
|
||||
{timezone, local}
|
||||
]},
|
||||
@@ -2774,11 +2799,7 @@ sent to an offline user will be stored on the server until that user comes
|
||||
online again. Thus it is very similar to how email works. Note that
|
||||
<TT>ejabberdctl</TT> has a command to delete expired messages
|
||||
(see section <A HREF="#ejabberdctl">4.1</A>).</P><DL CLASS="description"><DT CLASS="dt-description">
|
||||
<B><TT>{db_type, mnesia|odbc}</TT></B></DT><DD CLASS="dd-description">
|
||||
Define the type of storage where the module will create the tables and store user information.
|
||||
The default is to store in the internal Mnesia database.
|
||||
If <TT>odbc</TT> value is defined, make sure you have defined the database, see <A HREF="#database">3.2</A>.
|
||||
</DD><DT CLASS="dt-description"><B><TT>{access_max_user_messages, AccessName}</TT></B></DT><DD CLASS="dd-description">
|
||||
<B><TT>{access_max_user_messages, AccessName}</TT></B></DT><DD CLASS="dd-description">
|
||||
This option defines which access rule will be enforced to limit
|
||||
the maximum number of offline messages that a user can have (quota).
|
||||
When a user has too many offline messages, any new messages that he receive are discarded,
|
||||
@@ -2883,10 +2904,6 @@ subscription type (or globally).
|
||||
</P><DL CLASS="description"><DT CLASS="dt-description">
|
||||
<B><TT>{iqdisc, Discipline}</TT></B></DT><DD CLASS="dd-description"> This specifies
|
||||
the processing discipline for Blocking Communication (<TT>jabber:iq:privacy</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>).
|
||||
</DD><DT CLASS="dt-description"><B><TT>{db_type, mnesia|odbc}</TT></B></DT><DD CLASS="dd-description">
|
||||
Define the type of storage where the module will create the tables and store user information.
|
||||
The default is to store in the internal Mnesia database.
|
||||
If <TT>odbc</TT> value is defined, make sure you have defined the database, see <A HREF="#database">3.2</A>.
|
||||
</DD></DL><P> <A NAME="modprivate"></A> </P><!--TOC subsection <TT>mod_private</TT>-->
|
||||
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc54">3.3.16</A>  <A HREF="#modprivate"><TT>mod_private</TT></A></H3><!--SEC END --><P> <A NAME="modprivate"></A>
|
||||
</P><P>This module adds support for Private XML Storage (<A HREF="http://xmpp.org/extensions/xep-0049.html">XEP-0049</A>):
|
||||
@@ -2899,10 +2916,6 @@ of client-specific preferences; another is Bookmark Storage (<A HREF="http://xmp
|
||||
</P><DL CLASS="description"><DT CLASS="dt-description">
|
||||
<B><TT>{iqdisc, Discipline}</TT></B></DT><DD CLASS="dd-description"> This specifies
|
||||
the processing discipline for Private XML Storage (<TT>jabber:iq:private</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>).
|
||||
</DD><DT CLASS="dt-description"><B><TT>{db_type, mnesia|odbc}</TT></B></DT><DD CLASS="dd-description">
|
||||
Define the type of storage where the module will create the tables and store user information.
|
||||
The default is to store in the internal Mnesia database.
|
||||
If <TT>odbc</TT> value is defined, make sure you have defined the database, see <A HREF="#database">3.2</A>.
|
||||
</DD></DL><P> <A NAME="modproxy"></A> </P><!--TOC subsection <TT>mod_proxy65</TT>-->
|
||||
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc55">3.3.17</A>  <A HREF="#modproxy"><TT>mod_proxy65</TT></A></H3><!--SEC END --><P> <A NAME="modproxy"></A>
|
||||
</P><P>This module implements SOCKS5 Bytestreams (<A HREF="http://xmpp.org/extensions/xep-0065.html">XEP-0065</A>).
|
||||
@@ -3189,10 +3202,6 @@ It also supports Roster Versioning (<A HREF="http://xmpp.org/extensions/xep-0237
|
||||
</P><DL CLASS="description"><DT CLASS="dt-description">
|
||||
<B><TT>{iqdisc, Discipline}</TT></B></DT><DD CLASS="dd-description"> This specifies
|
||||
the processing discipline for Roster Management (<TT>jabber:iq:roster</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>).
|
||||
</DD><DT CLASS="dt-description"><B><TT>{db_type, mnesia|odbc}</TT></B></DT><DD CLASS="dd-description">
|
||||
Define the type of storage where the module will create the tables and store user information.
|
||||
The default is to store in the internal Mnesia database.
|
||||
If <TT>odbc</TT> value is defined, make sure you have defined the database, see <A HREF="#database">3.2</A>.
|
||||
</DD><DT CLASS="dt-description"><B><TT>{versioning, false|true}</TT></B></DT><DD CLASS="dd-description"> Enables
|
||||
Roster Versioning.
|
||||
This option is disabled by default.
|
||||
@@ -3203,7 +3212,7 @@ Enabling this option reduces the load for both ejabberd and the database.
|
||||
This option does not affect the client in any way.
|
||||
This option is only useful if Roster Versioning is enabled.
|
||||
This option is disabled by default.
|
||||
Important: if you use <TT>mod_shared_roster</TT> or <TT>mod_shared_roster_ldap</TT>,
|
||||
Important: if you use <TT>mod_shared_roster</TT>, <TT>mod_shared_roster_odbc</TT> or <TT>mod_shared_roster_ldap</TT>,
|
||||
you must disable this option.
|
||||
</DD></DL><P>This example configuration enables Roster Versioning with storage of current id:
|
||||
</P><PRE CLASS="verbatim">{modules,
|
||||
@@ -3251,13 +3260,7 @@ manually add all users to their rosters, and that they cannot permanently delete
|
||||
users from the shared roster groups.
|
||||
A shared roster group can have members from any XMPP server,
|
||||
but the presence will only be available from and to members
|
||||
of the same virtual host where the group is created.</P><P>Options:
|
||||
</P><DL CLASS="description"><DT CLASS="dt-description">
|
||||
<B><TT>{db_type, mnesia|odbc}</TT></B></DT><DD CLASS="dd-description">
|
||||
Define the type of storage where the module will create the tables and store user information.
|
||||
The default is to store in the internal Mnesia database.
|
||||
If <TT>odbc</TT> value is defined, make sure you have defined the database, see <A HREF="#database">3.2</A>.
|
||||
</DD></DL><P>Shared roster groups can be edited <EM>only</EM> via the Web Admin. Each group
|
||||
of the same virtual host where the group is created.</P><P>Shared roster groups can be edited <EM>only</EM> via the Web Admin. Each group
|
||||
has a unique identification and the following parameters:
|
||||
</P><DL CLASS="description"><DT CLASS="dt-description">
|
||||
<B>Name</B></DT><DD CLASS="dd-description"> The name of the group, which will be displayed in the roster.
|
||||
@@ -3604,10 +3607,6 @@ is replaced at start time with the real virtual host name.
|
||||
|
||||
</DD><DT CLASS="dt-description"><B><TT>{iqdisc, Discipline}</TT></B></DT><DD CLASS="dd-description"> This specifies
|
||||
the processing discipline for <TT>vcard-temp</TT> IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>).
|
||||
</DD><DT CLASS="dt-description"><B><TT>{db_type, mnesia|odbc}</TT></B></DT><DD CLASS="dd-description">
|
||||
Define the type of storage where the module will create the tables and store user information.
|
||||
The default is to store in the internal Mnesia database.
|
||||
If <TT>odbc</TT> value is defined, make sure you have defined the database, see <A HREF="#database">3.2</A>.
|
||||
</DD><DT CLASS="dt-description"><B><TT>{search, true|false}</TT></B></DT><DD CLASS="dd-description">This option specifies whether the search
|
||||
functionality is enabled or not
|
||||
If disabled, the option <TT>host</TT> will be ignored and the
|
||||
@@ -3623,7 +3622,7 @@ users who added some information to their vCard. The default value is
|
||||
</DD><DT CLASS="dt-description"><B><TT>{search_all_hosts, true|false}</TT></B></DT><DD CLASS="dd-description">If this option is set
|
||||
to <TT>true</TT>, search operations will apply to all virtual hosts. Otherwise
|
||||
only the current host will be searched. The default value is <TT>true</TT>.
|
||||
This option is available in <TT>mod_vcard</TT>when using Mnesia, but not when using ODBC storage.
|
||||
This option is available in <TT>mod_vcard</TT>, but not available in <TT>mod_vcard_odbc</TT>.
|
||||
</DD></DL><P>Examples:
|
||||
</P><UL CLASS="itemize"><LI CLASS="li-itemize">
|
||||
In this first situation, search results are limited to twenty items,
|
||||
@@ -3845,13 +3844,7 @@ it is replaced with the element generated by ejabberd.</P><P>By enabling this mo
|
||||
and each presence sent by a client produces hash retrieval and a
|
||||
presence stanza rewrite.
|
||||
For this reason, enabling this module will introduce a computational overhead
|
||||
in servers with clients that change frequently their presence.</P><P>Options:
|
||||
</P><DL CLASS="description"><DT CLASS="dt-description">
|
||||
<B><TT>{db_type, mnesia|odbc}</TT></B></DT><DD CLASS="dd-description">
|
||||
Define the type of storage where the module will create the tables and store user information.
|
||||
The default is to store in the internal Mnesia database.
|
||||
If <TT>odbc</TT> value is defined, make sure you have defined the database, see <A HREF="#database">3.2</A>.
|
||||
</DD></DL><P> <A NAME="modversion"></A> </P><!--TOC subsection <TT>mod_version</TT>-->
|
||||
in servers with clients that change frequently their presence.</P><P> <A NAME="modversion"></A> </P><!--TOC subsection <TT>mod_version</TT>-->
|
||||
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc69">3.3.31</A>  <A HREF="#modversion"><TT>mod_version</TT></A></H3><!--SEC END --><P> <A NAME="modversion"></A>
|
||||
</P><P>This module implements Software Version (<A HREF="http://xmpp.org/extensions/xep-0092.html">XEP-0092</A>). Consequently, it
|
||||
answers <TT>ejabberd</TT>’s version when queried.</P><P>Options:
|
||||
@@ -3896,6 +3889,7 @@ Add the option to the file <TT>ejabberd.cfg</TT>.
|
||||
In this example there is no restriction:
|
||||
</P><PRE CLASS="verbatim">{ejabberdctl_access_commands, []}.
|
||||
</PRE><P>If account <TT>robot1@example.org</TT> is registered in <TT>ejabberd</TT> with password <TT>abcdef</TT>
|
||||
(which MD5 is E8B501798950FC58AAD83C8C14978E),
|
||||
and <TT>ejabberd.cfg</TT> contains this setting:
|
||||
</P><PRE CLASS="verbatim">{hosts, ["example.org"]}.
|
||||
{acl, bots, {user, "robot1", "example.org"}}.
|
||||
@@ -3904,7 +3898,7 @@ and <TT>ejabberd.cfg</TT> contains this setting:
|
||||
</PRE><P>then you can do this in the shell:
|
||||
</P><PRE CLASS="verbatim">$ ejabberdctl registered_users example.org
|
||||
Error: no_auth_provided
|
||||
$ ejabberdctl --auth robot1 example.org abcdef registered_users example.org
|
||||
$ ejabberdctl --auth robot1 example.org E8B501798950FC58AAD83C8C14978E registered_users example.org
|
||||
robot1
|
||||
testuser1
|
||||
testuser2
|
||||
@@ -4044,8 +4038,6 @@ using jabberd1.4 formatted XML files.
|
||||
from other Jabber/XMPP servers
|
||||
There exist tutorials to
|
||||
<A HREF="http://www.ejabberd.im/migrate-to-ejabberd">migrate from other software to ejabberd</A>.
|
||||
</DD><DT CLASS="dt-description"><B><TT>export2odbc virtualhost directory</TT></B></DT><DD CLASS="dd-description">
|
||||
Export virtual host information from Mnesia tables to SQL files.
|
||||
</DD><DT CLASS="dt-description"><B><TT>delete_expired_messages</TT></B></DT><DD CLASS="dd-description"> This option can be used to delete old messages
|
||||
in offline storage. This might be useful when the number of offline messages
|
||||
is very high.
|
||||
@@ -4069,7 +4061,8 @@ The authentication information is provided when executing a command,
|
||||
and is Username, Hostname and Password of a local XMPP account
|
||||
that has permission to execute the corresponding command.
|
||||
This means that the account must be registered in the local ejabberd,
|
||||
because the information will be verified.</P><P>When one or several access restrictions are defined and the
|
||||
because the information will be verified.
|
||||
It is possible to provide the plaintext password or its MD5 sum.</P><P>When one or several access restrictions are defined and the
|
||||
authentication information is provided,
|
||||
each restriction is verified until one matches completely:
|
||||
the account matches the Access rule,
|
||||
|
||||
+237
-141
@@ -66,7 +66,9 @@
|
||||
\newcommand{\module}[1]{\texttt{#1}}
|
||||
\newcommand{\modadhoc}{\module{mod\_adhoc}}
|
||||
\newcommand{\modannounce}{\module{mod\_announce}}
|
||||
\newcommand{\modannounceodbc}{\module{mod\_announce\_odbc}}
|
||||
\newcommand{\modblocking}{\module{mod\_blocking}}
|
||||
\newcommand{\modblockingodbc}{\module{mod\_blocking\_odbc}}
|
||||
\newcommand{\modcaps}{\module{mod\_caps}}
|
||||
\newcommand{\modconfigure}{\module{mod\_configure}}
|
||||
\newcommand{\moddisco}{\module{mod\_disco}}
|
||||
@@ -74,29 +76,40 @@
|
||||
\newcommand{\modhttpbind}{\module{mod\_http\_bind}}
|
||||
\newcommand{\modhttpfileserver}{\module{mod\_http\_fileserver}}
|
||||
\newcommand{\modirc}{\module{mod\_irc}}
|
||||
\newcommand{\modircodbc}{\module{mod\_irc\_odbc}}
|
||||
\newcommand{\modlast}{\module{mod\_last}}
|
||||
\newcommand{\modlastodbc}{\module{mod\_last\_odbc}}
|
||||
\newcommand{\modmuc}{\module{mod\_muc}}
|
||||
\newcommand{\modmucodbc}{\module{mod\_muc\_odbc}}
|
||||
\newcommand{\modmuclog}{\module{mod\_muc\_log}}
|
||||
\newcommand{\modmulticast}{\module{mod\_multicast}}
|
||||
\newcommand{\modoffline}{\module{mod\_offline}}
|
||||
\newcommand{\modofflineodbc}{\module{mod\_offline\_odbc}}
|
||||
\newcommand{\modping}{\module{mod\_ping}}
|
||||
\newcommand{\modprescounter}{\module{mod\_pres\_counter}}
|
||||
\newcommand{\modprivacy}{\module{mod\_privacy}}
|
||||
\newcommand{\modprivacyodbc}{\module{mod\_privacy\_odbc}}
|
||||
\newcommand{\modprivate}{\module{mod\_private}}
|
||||
\newcommand{\modprivateodbc}{\module{mod\_private\_odbc}}
|
||||
\newcommand{\modproxy}{\module{mod\_proxy65}}
|
||||
\newcommand{\modpubsub}{\module{mod\_pubsub}}
|
||||
\newcommand{\modpubsubodbc}{\module{mod\_pubsub\_odbc}}
|
||||
\newcommand{\modregister}{\module{mod\_register}}
|
||||
\newcommand{\modregisterweb}{\module{mod\_register\_web}}
|
||||
\newcommand{\modroster}{\module{mod\_roster}}
|
||||
\newcommand{\modrosterodbc}{\module{mod\_roster\_odbc}}
|
||||
\newcommand{\modservicelog}{\module{mod\_service\_log}}
|
||||
\newcommand{\modsharedroster}{\module{mod\_shared\_roster}}
|
||||
\newcommand{\modsharedrosterodbc}{\module{mod\_shared\_roster\_odbc}}
|
||||
\newcommand{\modsharedrosterldap}{\module{mod\_shared\_roster\_ldap}}
|
||||
\newcommand{\modsic}{\module{mod\_sic}}
|
||||
\newcommand{\modstats}{\module{mod\_stats}}
|
||||
\newcommand{\modtime}{\module{mod\_time}}
|
||||
\newcommand{\modvcard}{\module{mod\_vcard}}
|
||||
\newcommand{\modvcardldap}{\module{mod\_vcard\_ldap}}
|
||||
\newcommand{\modvcardodbc}{\module{mod\_vcard\_odbc}}
|
||||
\newcommand{\modvcardxupdate}{\module{mod\_vcard\_xupdate}}
|
||||
\newcommand{\modvcardxupdateodbc}{\module{mod\_vcard\_xupdate\_odbc}}
|
||||
\newcommand{\modversion}{\module{mod\_version}}
|
||||
|
||||
%% Contributed modules
|
||||
@@ -117,11 +130,6 @@ the processing discipline for #1 IQ queries (see section~\ref{modiqdiscoption}).
|
||||
hostname of the virtual host with the prefix `\jid{#1.}'. The keyword "@HOST@"
|
||||
is replaced at start time with the real virtual host name.
|
||||
}
|
||||
\newcommand{\dbtype}{\titem{\{db\_type, mnesia|odbc\}} \ind{options!dbtype}
|
||||
Define the type of storage where the module will create the tables and store user information.
|
||||
The default is to store in the internal Mnesia database.
|
||||
If \term{odbc} value is defined, make sure you have defined the database, see~\ref{database}.
|
||||
}
|
||||
|
||||
%% Title page
|
||||
\include{version}
|
||||
@@ -246,6 +254,8 @@ go to the Windows service settings and set ejabberd to be automatically started.
|
||||
Note that the Windows service is a feature still in development,
|
||||
and for example it doesn't read the file ejabberdctl.cfg.
|
||||
|
||||
The OSX binary installer works on OSX 10.6 and newer.
|
||||
|
||||
On a *nix system, if you want ejabberd to be started as daemon at boot time,
|
||||
copy \term{ejabberd.init} from the 'bin' directory to something like \term{/etc/init.d/ejabberd}
|
||||
(depending on your distribution).
|
||||
@@ -376,10 +386,34 @@ Some options that you may be interested in modifying:
|
||||
\titem{--enable-pam}
|
||||
Enable the PAM authentication method (see section \ref{pam}).
|
||||
|
||||
\titem{--enable-odbc or --enable-mssql}
|
||||
\titem{--enable-mssql}
|
||||
Required if you want to use an external database.
|
||||
See section~\ref{database} for more information.
|
||||
|
||||
\titem{--enable-tools}
|
||||
Enable the use of development tools.
|
||||
|
||||
\titem{--enable-mysql}
|
||||
Enable MySQL support (see section \ref{mysql}).
|
||||
|
||||
\titem{--enable-pgsql}
|
||||
Enable PostgreSQL support (see section \ref{pgsql}).
|
||||
|
||||
\titem{--enable-zlib}
|
||||
Enable Stream Compression (XEP-0138) using zlib.
|
||||
|
||||
\titem{--enable-stun}
|
||||
Enable STUN support (see section \ref{stun}).
|
||||
|
||||
\titem{--enable-riak}
|
||||
Enable Riak support.
|
||||
|
||||
\titem{--enable-iconv}
|
||||
Enable iconv support. This is needed for \term{mod\_irc} (see seciont \ref{modirc}).
|
||||
|
||||
\titem{--enable-debug}
|
||||
Compile with \term{+debug\_info} enabled.
|
||||
|
||||
\titem{--enable-full-xml}
|
||||
Enable the use of XML based optimisations.
|
||||
It will for example use CDATA to escape characters in the XMPP stream.
|
||||
@@ -391,6 +425,9 @@ Some options that you may be interested in modifying:
|
||||
\titem{--enable-nif}
|
||||
Replaces some critical Erlang functions with equivalents written in C to improve performance.
|
||||
This feature requires Erlang/OTP R13B04 or higher.
|
||||
|
||||
\titem{--enable-flash-hack}
|
||||
Enable support for non-standard XML socket clients of Adobe Flash 8 and lower.
|
||||
\end{description}
|
||||
|
||||
\makesubsection{install}{Install}
|
||||
@@ -827,6 +864,9 @@ The available modules, their purpose and the options allowed by each one are:
|
||||
Handles incoming HTTP connections.\\
|
||||
Options: \texttt{captcha}, \texttt{certfile}, \texttt{default\_host}, \texttt{http\_bind}, \texttt{http\_poll},
|
||||
\texttt{request\_handlers}, \texttt{tls}, \texttt{trusted\_proxies}, \texttt{web\_admin}\\
|
||||
\titem{\texttt{ejabberd\_xmlrpc}}
|
||||
Handles incoming XML-RPC requests to execute ejabberd commands (see \ref{eja-commands}).\\
|
||||
Options: \texttt{access\_commands}, \texttt{timeout}\\
|
||||
\end{description}
|
||||
|
||||
|
||||
@@ -836,6 +876,19 @@ This is a detailed description of each option allowed by the listening modules:
|
||||
\begin{description}
|
||||
\titem{\{access, AccessName\}} \ind{options!access}This option defines
|
||||
access to the port. The default value is \term{all}.
|
||||
\titem{\{access\_commands, AccessCommands\}} \ind{options!accesscommands}
|
||||
This option allows to define a list of access restrictions (see \ref{accesscommands}).
|
||||
If this option is present, then XML-RPC calls must include as
|
||||
first argument a struct with a user, server and password of an
|
||||
account in ejabberd that has privileges in Access.
|
||||
If the option is not present, such struct must not be provided.
|
||||
The default value is to not define any restriction: \term{\[\]}
|
||||
When one or several access restrictions are defined and the
|
||||
XML-RPC call provides authentication for an account, each
|
||||
restriction is verified until one matches completely:
|
||||
the account matches the Access rule,
|
||||
the command name is listed in CommandNames,
|
||||
and the provided arguments do not contradict Arguments.
|
||||
\titem{\{backlog, Value\}} \ind{options!backlog}The backlog value
|
||||
defines the maximum length that the queue of pending connections may
|
||||
grow to. This should be increased if the server is going to handle
|
||||
@@ -943,6 +996,9 @@ This is a detailed description of each option allowed by the listening modules:
|
||||
No unencrypted connections will be allowed.
|
||||
You should also set the \option{certfile} option.
|
||||
You can define a certificate file for a specific domain using the global option \option{domain\_certfile}.
|
||||
\titem{\{timeout, Integer\}} \ind{options!timeout}
|
||||
Timeout of the connections, expressed in milliseconds.
|
||||
Default: 5000
|
||||
\titem{tls} \ind{options!tls}\ind{TLS}This option specifies that traffic on
|
||||
the port will be encrypted using SSL immediately after connecting.
|
||||
This was the traditional encryption method in the early Jabber software,
|
||||
@@ -1089,6 +1145,8 @@ In this example, the following configuration defines that:
|
||||
example in section~\ref{webadmin} shows how exactly this can be done.
|
||||
\item All users except for the administrators have a traffic of limit
|
||||
1,000\,Bytes/second
|
||||
\item The XML-RPC service listens in port 4560 and allows only
|
||||
a specific account, to request registrations and unregistrations in a specific host.
|
||||
\item \ind{transports!AIM}The
|
||||
\footahref{http://www.ejabberd.im/pyaimt}{AIM transport}
|
||||
\jid{aim.example.org} is connected to port 5233 on localhost IP addresses
|
||||
@@ -1119,6 +1177,8 @@ In this example, the following configuration defines that:
|
||||
{shaper, normal, {maxrate, 1000}}.
|
||||
{access, c2s_shaper, [{none, admin},
|
||||
{normal, all}]}.
|
||||
{acl, xmlrpc_bot, {user, "xmlrpc-robot", "example.org"}}.
|
||||
{access, xmlrpc_access, [{allow, xmlrpc_bot}]}.
|
||||
{listen,
|
||||
[{5222, ejabberd_c2s, [
|
||||
{access, c2s},
|
||||
@@ -1138,6 +1198,11 @@ In this example, the following configuration defines that:
|
||||
http_poll,
|
||||
web_admin
|
||||
]},
|
||||
{4560, ejabberd_xmlrpc, [
|
||||
{access_commands, [
|
||||
{xmlrpc_access, [register, unregister], [{host, "example.org"}]}
|
||||
]}
|
||||
]},
|
||||
{{5233, {127, 0, 0, 1}}, ejabberd_service, [
|
||||
{hosts, ["aim.example.org"],
|
||||
[{password, "aimsecret"}]}
|
||||
@@ -1216,6 +1281,7 @@ The following authentication methods are supported by \ejabberd{}:
|
||||
\ref{mssql} and \ref{odbc}.
|
||||
\item anonymous --- See section~\ref{saslanonymous}.
|
||||
\item pam --- See section~\ref{pam}.
|
||||
\item riak --- See section~\ref{riak}.
|
||||
\end{itemize}
|
||||
|
||||
Account creation is only supported by internal, external and odbc methods.
|
||||
@@ -1305,7 +1371,7 @@ These are the specific options:
|
||||
the authentication information since the user last disconnected,
|
||||
to verify again the user authentication without querying again the extauth script.
|
||||
Note: caching should not be enabled in a host if internal auth is also enabled.
|
||||
If caching is enabled, \term{mod\_last} must be enabled also in that vhost.
|
||||
If caching is enabled, \term{mod\_last} or \term{mod\_last\_odbc} must be enabled also in that vhost.
|
||||
\end{description}
|
||||
|
||||
This example sets external authentication, the extauth script, enables caching for 10 minutes,
|
||||
@@ -1931,14 +1997,8 @@ For example:
|
||||
\makesubsection{mysql}{MySQL}
|
||||
\ind{MySQL}\ind{MySQL!schema}
|
||||
|
||||
Although this section will describe \ejabberd{}'s configuration when you want to
|
||||
use the native MySQL driver, it does not describe MySQL's installation and
|
||||
database creation. Check the MySQL documentation and the tutorial \footahref{http://support.process-one.net/doc/display/MESSENGER/Using+ejabberd+with+MySQL+native+driver}{Using ejabberd with MySQL native driver} for information regarding these topics.
|
||||
Note that the tutorial contains information about \ejabberd{}'s configuration
|
||||
which is duplicate to this section.
|
||||
|
||||
Moreover, the file mysql.sql in the directory src/odbc might be interesting for
|
||||
you. This file contains the \ejabberd{} schema for MySQL. At the end of the file
|
||||
There is a file \term{mysql.sql} in the directory \term{odbc}.
|
||||
This file contains the \ejabberd{} schema for MySQL. At the end of the file
|
||||
you can find information to update your database schema.
|
||||
|
||||
|
||||
@@ -1946,19 +2006,13 @@ you can find information to update your database schema.
|
||||
\ind{MySQL!Driver Compilation}
|
||||
|
||||
You can skip this step if you installed \ejabberd{} using a binary installer or
|
||||
if the binary packages of \ejabberd{} you are using include support for MySQL.
|
||||
if the binary packages of \ejabberd{} you are using include support for ODBC.
|
||||
|
||||
\begin{enumerate}
|
||||
\item First, install the \footahref{http://support.process-one.net/doc/display/CONTRIBS/Yxa}{Erlang
|
||||
MySQL library}. Make sure the compiled files are in your Erlang path; you can
|
||||
put them for example in the same directory as your \ejabberd{} .beam files.
|
||||
\item Then, configure and install \ejabberd{} with ODBC support enabled (this is
|
||||
also needed for native MySQL support!). This can be done, by using next
|
||||
commands:
|
||||
Use \term{--enable-mysql} configure option in order to build \ejabberd{} with
|
||||
MySQL support:
|
||||
\begin{verbatim}
|
||||
./configure --enable-odbc && make install
|
||||
./configure --enable-mysql && make install
|
||||
\end{verbatim}
|
||||
\end{enumerate}
|
||||
|
||||
|
||||
\makesubsubsection{configuremysql}{Database Connection}
|
||||
@@ -2021,24 +2075,19 @@ MySQL interface. Anyway, the first configuration step is to define the odbc
|
||||
\ind{MySQL!storage}
|
||||
|
||||
MySQL also can be used to store information into from several \ejabberd{}
|
||||
modules. See section~\ref{modoverview} to see which modules can be used with
|
||||
modules. See section~\ref{modoverview} to see which modules have a version
|
||||
with the `\_odbc'. This suffix indicates that the module can be used with
|
||||
relational databases like MySQL. To enable storage to your database, just make
|
||||
sure that your database is running well (see previous sections), and add the
|
||||
module option \term{\{db\_type, odbc\}}.
|
||||
sure that your database is running well (see previous sections), and replace the
|
||||
suffix-less or ldap module variant with the odbc module variant. Keep in mind
|
||||
that you cannot have several variants of the same module loaded!
|
||||
|
||||
\makesubsection{mssql}{Microsoft SQL Server}
|
||||
\ind{Microsoft SQL Server}\ind{Microsoft SQL Server!schema}
|
||||
|
||||
Although this section will describe \ejabberd{}'s configuration when you want to
|
||||
use Microsoft SQL Server, it does not describe Microsoft SQL Server's
|
||||
installation and database creation. Check the MySQL documentation and the
|
||||
tutorial \footahref{http://support.process-one.net/doc/display/MESSENGER/Using+ejabberd+with+MySQL+native+driver}{Using ejabberd with MySQL native driver} for information regarding these topics.
|
||||
Note that the tutorial contains information about \ejabberd{}'s configuration
|
||||
which is duplicate to this section.
|
||||
|
||||
Moreover, the file mssql.sql in the directory src/odbc might be interesting for
|
||||
you. This file contains the \ejabberd{} schema for Microsoft SQL Server. At the end
|
||||
of the file you can find information to update your database schema.
|
||||
There is a file \term{mssql.sql} in the directory \term{odbc}.
|
||||
This file contains the \ejabberd{} schema for Microsoft SQL Server. At the end of the file
|
||||
you can find information to update your database schema.
|
||||
|
||||
|
||||
\makesubsubsection{compilemssql}{Driver Compilation}
|
||||
@@ -2047,20 +2096,29 @@ of the file you can find information to update your database schema.
|
||||
You can skip this step if you installed \ejabberd{} using a binary installer or
|
||||
if the binary packages of \ejabberd{} you are using include support for ODBC.
|
||||
|
||||
If you want to use Microsoft SQL Server with ODBC, you need to configure,
|
||||
compile and install \ejabberd{} with support for ODBC and Microsoft SQL Server
|
||||
enabled. This can be done, by using next commands:
|
||||
Use \term{--enable-mssql} configure option in order to build \ejabberd{} with
|
||||
Microsoft SQL Server support:
|
||||
\begin{verbatim}
|
||||
./configure --enable-odbc --enable-mssql && make install
|
||||
./configure --enable-mssql && make install
|
||||
\end{verbatim}
|
||||
|
||||
|
||||
\makesubsubsection{configuremssql}{Database Connection}
|
||||
\ind{Microsoft SQL Server!Database Connection}
|
||||
|
||||
The configuration of Database Connection for a Microsoft SQL Server
|
||||
is the same as the configuration for
|
||||
ODBC compatible servers (see section~\ref{configureodbc}).
|
||||
By default \ejabberd{} opens 10 connections to the database for each virtual host.
|
||||
Use this option to modify the value:
|
||||
\begin{verbatim}
|
||||
{odbc_pool_size, 10}.
|
||||
\end{verbatim}
|
||||
|
||||
You can configure an interval to make a dummy SQL request
|
||||
to keep alive the connections to the database.
|
||||
The default value is 'undefined', so no keepalive requests are made.
|
||||
Specify in seconds: for example 28800 means 8 hours.
|
||||
\begin{verbatim}
|
||||
{odbc_keepalive_interval, undefined}.
|
||||
\end{verbatim}
|
||||
|
||||
|
||||
\makesubsubsection{mssqlauth}{Authentication}
|
||||
@@ -2068,29 +2126,25 @@ ODBC compatible servers (see section~\ref{configureodbc}).
|
||||
|
||||
%TODO: not sure if this section is right!!!!!!
|
||||
|
||||
The configuration of Authentication for a Microsoft SQL Server
|
||||
is the same as the configuration for
|
||||
The configuration of Microsoft SQL Server is the same as the configuration of
|
||||
ODBC compatible servers (see section~\ref{odbcauth}).
|
||||
|
||||
\makesubsubsection{mssqlstorage}{Storage}
|
||||
\ind{Microsoft SQL Server!storage}
|
||||
|
||||
Microsoft SQL Server also can be used to store information into from several
|
||||
modules. See section~\ref{modoverview} to see which modules can be used with
|
||||
relational databases like MySQL. To enable storage to your database, just make
|
||||
sure that your database is running well (see previous sections), and add the
|
||||
module option \term{\{db\_type, odbc\}}.
|
||||
\ejabberd{} modules. See section~\ref{modoverview} to see which modules have
|
||||
a version with the `\_odbc'. This suffix indicates that the module can be used
|
||||
with relational databases like Microsoft SQL Server. To enable storage to your
|
||||
database, just make sure that your database is running well (see previous
|
||||
sections), and replace the suffix-less or ldap module variant with the odbc
|
||||
module variant. Keep in mind that you cannot have several variants of the same
|
||||
module loaded!
|
||||
|
||||
\makesubsection{pgsql}{PostgreSQL}
|
||||
\ind{PostgreSQL}\ind{PostgreSQL!schema}
|
||||
|
||||
Although this section will describe \ejabberd{}'s configuration when you want to
|
||||
use the native PostgreSQL driver, it does not describe PostgreSQL's installation
|
||||
and database creation. Check the PostgreSQL documentation and the tutorial \footahref{http://support.process-one.net/doc/display/MESSENGER/Using+ejabberd+with+MySQL+native+driver}{Using ejabberd with MySQL native driver} for information regarding these topics.
|
||||
Note that the tutorial contains information about \ejabberd{}'s configuration
|
||||
which is duplicate to this section.
|
||||
|
||||
Also the file pg.sql in the directory src/odbc might be interesting for you.
|
||||
There is a file \term{pg.sql} in the directory \term{odbc}.
|
||||
This file contains the \ejabberd{} schema for PostgreSQL. At the end of the file
|
||||
you can find information to update your database schema.
|
||||
|
||||
@@ -2102,19 +2156,11 @@ You can skip this step if you installed \ejabberd{} using a binary installer or
|
||||
if the binary packages of \ejabberd{} you are using include support for
|
||||
PostgreSQL.
|
||||
|
||||
\begin{enumerate}
|
||||
\item First, install the Erlang pgsql library from
|
||||
\footahref{http://www.ejabberd.im/ejabberd-modules/}{ejabberd-modules SVN repository}.
|
||||
Make sure the compiled
|
||||
files are in your Erlang path; you can put them for example in the same
|
||||
directory as your \ejabberd{} .beam files.
|
||||
\item Then, configure, compile and install \ejabberd{} with ODBC support enabled
|
||||
(this is also needed for native PostgreSQL support!). This can be done, by
|
||||
using next commands:
|
||||
Use \term{--enable-pgsql} configure option in order to build \ejabberd{} with
|
||||
PostgreSQL support:
|
||||
\begin{verbatim}
|
||||
./configure --enable-odbc && make install
|
||||
./configure --enable-pgsql && make install
|
||||
\end{verbatim}
|
||||
\end{enumerate}
|
||||
|
||||
|
||||
\makesubsubsection{configurepgsql}{Database Connection}
|
||||
@@ -2171,39 +2217,16 @@ PostgreSQL interface. Anyway, the first configuration step is to define the odbc
|
||||
\ind{PostgreSQL!storage}
|
||||
|
||||
PostgreSQL also can be used to store information into from several \ejabberd{}
|
||||
modules. See section~\ref{modoverview} to see which modules can be used with
|
||||
relational databases like MySQL. To enable storage to your database, just make
|
||||
sure that your database is running well (see previous sections), and add the
|
||||
module option \term{\{db\_type, odbc\}}.
|
||||
modules. See section~\ref{modoverview} to see which modules have a version
|
||||
with the `\_odbc'. This suffix indicates that the module can be used with
|
||||
relational databases like PostgreSQL. To enable storage to your database, just
|
||||
make sure that your database is running well (see previous sections), and
|
||||
replace the suffix-less or ldap module variant with the odbc module variant.
|
||||
Keep in mind that you cannot have several variants of the same module loaded!
|
||||
|
||||
\makesubsection{odbc}{ODBC Compatible}
|
||||
\ind{databases!ODBC}
|
||||
|
||||
Although this section will describe \ejabberd{}'s configuration when you want to
|
||||
use the ODBC driver, it does not describe the installation and database creation
|
||||
of your database. Check the documentation of your database. The tutorial \footahref{http://support.process-one.net/doc/display/MESSENGER/Using+ejabberd+with+MySQL+native+driver}{Using ejabberd with MySQL native driver} also can help you. Note that the tutorial
|
||||
contains information about \ejabberd{}'s configuration which is duplicate to
|
||||
this section.
|
||||
|
||||
|
||||
\makesubsubsection{compileodbc}{Driver Compilation}
|
||||
|
||||
You can skip this step if you installed \ejabberd{} using a binary installer or
|
||||
if the binary packages of \ejabberd{} you are using include support for
|
||||
ODBC.
|
||||
|
||||
\begin{enumerate}
|
||||
\item First, install the \footahref{http://support.process-one.net/doc/display/CONTRIBS/Yxa}{Erlang
|
||||
MySQL library}. Make sure the compiled files are in your Erlang path; you can
|
||||
put them for example in the same directory as your \ejabberd{} .beam files.
|
||||
\item Then, configure, compile and install \ejabberd{} with ODBC support
|
||||
enabled. This can be done, by using next commands:
|
||||
\begin{verbatim}
|
||||
./configure --enable-odbc && make install
|
||||
\end{verbatim}
|
||||
\end{enumerate}
|
||||
|
||||
|
||||
\makesubsubsection{configureodbc}{Database Connection}
|
||||
\ind{ODBC!Database Connection}
|
||||
|
||||
@@ -2246,11 +2269,13 @@ example:
|
||||
\ind{ODBC!storage}
|
||||
|
||||
An ODBC compatible database also can be used to store information into from
|
||||
several \ejabberd{}
|
||||
modules. See section~\ref{modoverview} to see which modules can be used with
|
||||
relational databases like MySQL. To enable storage to your database, just make
|
||||
sure that your database is running well (see previous sections), and add the
|
||||
module option \term{\{db\_type, odbc\}}.
|
||||
several \ejabberd{} modules. See section~\ref{modoverview} to see which
|
||||
modules have a version with the `\_odbc'. This suffix indicates that the module
|
||||
can be used with ODBC compatible relational databases. To enable storage to your
|
||||
database, just make sure that your database is running well (see previous
|
||||
sections), and replace the suffix-less or ldap module variant with the odbc
|
||||
module variant. Keep in mind that you cannot have several variants of the same
|
||||
module loaded!
|
||||
|
||||
\makesubsection{ldap}{LDAP}
|
||||
\ind{databases!LDAP}
|
||||
@@ -2568,7 +2593,10 @@ The following table lists all modules included in \ejabberd{}.
|
||||
\hline
|
||||
\hline \modadhoc{} & Ad-Hoc Commands (\xepref{0050}) & \\
|
||||
\hline \ahrefloc{modannounce}{\modannounce{}} & Manage announcements & recommends \modadhoc{} \\
|
||||
\hline \ahrefloc{modannounce}{\modannounceodbc{}} & Manage announcements & recommends \modadhoc{} \\
|
||||
& & supported DB (*) \\
|
||||
\hline \modblocking{} & Simple Communications Blocking (\xepref{0191}) & \modprivacy{} \\
|
||||
\hline \modblockingodbc{} & Simple Communications Blocking (\xepref{0191}) & \modprivacyodbc{} \\
|
||||
\hline \modcaps{} & Entity Capabilities (\xepref{0115}) & \\
|
||||
\hline \modconfigure{} & Server configuration using Ad-Hoc & \modadhoc{} \\
|
||||
\hline \ahrefloc{moddisco}{\moddisco{}} & Service Discovery (\xepref{0030}) & \\
|
||||
@@ -2576,29 +2604,43 @@ The following table lists all modules included in \ejabberd{}.
|
||||
\hline \ahrefloc{modhttpbind}{\modhttpbind{}} & XMPP over Bosh service (HTTP Binding) & \\
|
||||
\hline \ahrefloc{modhttpfileserver}{\modhttpfileserver{}} & Small HTTP file server & \\
|
||||
\hline \ahrefloc{modirc}{\modirc{}} & IRC transport & \\
|
||||
\hline \ahrefloc{modirc}{\modircodbc{}} & IRC transport & supported DB (*) \\
|
||||
\hline \ahrefloc{modlast}{\modlast{}} & Last Activity (\xepref{0012}) & \\
|
||||
\hline \ahrefloc{modlast}{\modlastodbc{}} & Last Activity (\xepref{0012}) & supported DB (*) \\
|
||||
\hline \ahrefloc{modmuc}{\modmuc{}} & Multi-User Chat (\xepref{0045}) & \\
|
||||
\hline \ahrefloc{modmuclog}{\modmuclog{}} & Multi-User Chat room logging & \modmuc{} \\
|
||||
\hline \ahrefloc{modmuc}{\modmucodbc{}} & Multi-User Chat (\xepref{0045}) & supported DB (*) \\
|
||||
\hline \ahrefloc{modmuclog}{\modmuclog{}} & Multi-User Chat room logging & \modmuc{} or \modmucodbc{} \\
|
||||
\hline \ahrefloc{modmulticast}{\modmulticast{}} & Multicast service (\xepref{0033}) & \\
|
||||
\hline \ahrefloc{modoffline}{\modoffline{}} & Offline message storage (\xepref{0160}) & \\
|
||||
\hline \ahrefloc{modoffline}{\modofflineodbc{}} & Offline message storage (\xepref{0160}) & supported DB (*) \\
|
||||
\hline \ahrefloc{modping}{\modping{}} & XMPP Ping and periodic keepalives (\xepref{0199}) & \\
|
||||
\hline \ahrefloc{modprescounter}{\modprescounter{}} & Detect presence subscription flood & \\
|
||||
\hline \ahrefloc{modprivacy}{\modprivacy{}} & Blocking Communication (\xepref{0016}) & \\
|
||||
\hline \ahrefloc{modprivacy}{\modprivacyodbc{}} & Blocking Communication (\xepref{0016}) & supported DB (*) \\
|
||||
\hline \ahrefloc{modprivate}{\modprivate{}} & Private XML Storage (\xepref{0049}) & \\
|
||||
\hline \ahrefloc{modprivate}{\modprivateodbc{}} & Private XML Storage (\xepref{0049}) & supported DB (*) \\
|
||||
\hline \ahrefloc{modproxy}{\modproxy{}} & SOCKS5 Bytestreams (\xepref{0065}) & \\
|
||||
\hline \ahrefloc{modpubsub}{\modpubsub{}} & Pub-Sub (\xepref{0060}), PEP (\xepref{0163}) & \modcaps{} \\
|
||||
\hline \ahrefloc{modpubsub}{\modpubsubodbc{}} & Pub-Sub (\xepref{0060}), PEP (\xepref{0163}) & supported DB (*) and \modcaps{} \\
|
||||
\hline \ahrefloc{modregister}{\modregister{}} & In-Band Registration (\xepref{0077}) & \\
|
||||
\hline \ahrefloc{modregisterweb}{\modregisterweb{}} & Web for Account Registrations & \\
|
||||
\hline \ahrefloc{modroster}{\modroster{}} & Roster management (XMPP IM) & \\
|
||||
\hline \ahrefloc{modroster}{\modrosterodbc{}} & Roster management (XMPP IM) & supported DB (*) \\
|
||||
\hline \ahrefloc{modservicelog}{\modservicelog{}} & Copy user messages to logger service & \\
|
||||
\hline \ahrefloc{modsharedroster}{\modsharedroster{}} & Shared roster management & \modroster{} \\
|
||||
\hline \ahrefloc{modsharedrosterldap}{\modsharedrosterldap{}} & LDAP Shared roster management & \modroster{} \\
|
||||
\hline \ahrefloc{modsharedroster}{\modsharedroster{}} & Shared roster management & \modroster{} or \\
|
||||
& & \modrosterodbc\\
|
||||
\hline \ahrefloc{modsharedroster}{\modsharedrosterodbc{}} & Shared roster management & supported DB (*) and\\
|
||||
& & \modroster{} or \modrosterodbc\\
|
||||
\hline \ahrefloc{modsharedrosterldap}{\modsharedrosterldap{}} & LDAP Shared roster management & \modroster{} or \\
|
||||
& & \modrosterodbc\\
|
||||
\hline \ahrefloc{modsic}{\modsic{}} & Server IP Check (\xepref{0279}) & \\
|
||||
\hline \ahrefloc{modstats}{\modstats{}} & Statistics Gathering (\xepref{0039}) & \\
|
||||
\hline \ahrefloc{modtime}{\modtime{}} & Entity Time (\xepref{0202}) & \\
|
||||
\hline \ahrefloc{modvcard}{\modvcard{}} & vcard-temp (\xepref{0054}) & \\
|
||||
\hline \ahrefloc{modvcardldap}{\modvcardldap{}} & vcard-temp (\xepref{0054}) & LDAP server \\
|
||||
\hline \ahrefloc{modvcardxupdate}{\modvcardxupdate{}} & vCard-Based Avatars (\xepref{0153}) & \modvcard{} \\
|
||||
\hline \ahrefloc{modvcard}{\modvcardodbc{}} & vcard-temp (\xepref{0054}) & supported DB (*) \\
|
||||
\hline \ahrefloc{modvcardxupdate}{\modvcardxupdate{}} & vCard-Based Avatars (\xepref{0153}) & \modvcard{} or \modvcardodbc{} \\
|
||||
\hline \ahrefloc{modvcardxupdate}{\modvcardxupdateodbc{}} & vCard-Based Avatars (\xepref{0153}) & \modvcard{} or \modvcardodbc{} \\
|
||||
\hline \ahrefloc{modversion}{\modversion{}} & Software Version (\xepref{0092}) & \\
|
||||
\hline
|
||||
\end{tabular}
|
||||
@@ -2610,11 +2652,37 @@ The following table lists all modules included in \ejabberd{}.
|
||||
|
||||
You can see which database backend each module needs by looking at the suffix:
|
||||
\begin{itemize}
|
||||
\item No suffix, this means that the module uses Erlang's built-in database
|
||||
Mnesia as backend, or a ODBC database in some cases (see~\ref{database}).
|
||||
\item No suffix, this means that the modules uses Erlang's built-in database
|
||||
Mnesia as backend.
|
||||
\item `\_odbc', this means that the module needs a supported database
|
||||
(see~\ref{database}) as backend.
|
||||
\item `\_ldap', this means that the module needs an LDAP server as backend.
|
||||
\end{itemize}
|
||||
|
||||
If you want to,
|
||||
it is possible to use a relational database to store the tables created by some ejabberd modules.
|
||||
You can do this by changing the module name to a name with an
|
||||
\term{\_odbc} suffix in \ejabberd{} config file. You can use a relational
|
||||
database for the following data:
|
||||
|
||||
\begin{itemize}
|
||||
\item Last connection date and time: Use \term{mod\_last\_odbc} instead of
|
||||
\term{mod\_last}.
|
||||
\item Offline messages: Use \term{mod\_offline\_odbc} instead of
|
||||
\term{mod\_offline}.
|
||||
\item Rosters: Use \term{mod\_roster\_odbc} instead of \term{mod\_roster}.
|
||||
\item Shared Rosters: Use \term{mod\_shared\_roster\_odbc} instead of \term{mod\_shared\_roster}.
|
||||
\item Users' VCARD: Use \term{mod\_vcard\_odbc} instead of \term{mod\_vcard}.
|
||||
\item vCard-Based Avatars: Use \term{mod\_vcard\_xupdate\_odbc} instead of \term{mod\_vcard\_xupdate}.
|
||||
\item Private XML storage: Use \term{mod\_private\_odbc} instead of \term{mod\_private}.
|
||||
\item User rules for blocking communications: Use \term{mod\_privacy\_odbc} instead of \term{mod\_privacy}.
|
||||
\item Simple Communications Blocking: Use \term{mod\_blocking\_odbc} instead of \term{mod\_blocking}.
|
||||
\item Pub-Sub nodes, items and subscriptions: Use \term{mod\_pubsub\_odbc} instead of \term{mod\_pubsub}.
|
||||
\item Multi-user chats: Use \term{mod\_muc\_odbc} instead of \term{mod\_muc}.
|
||||
\item Manage announcements: Use \term{mod\_announce\_odbc} instead of \term{mod\_announce}.
|
||||
\item IRC transport: Use \term{mod\_irc\_odbc} instead of \term{mod\_irc}.
|
||||
\end{itemize}
|
||||
|
||||
You can find more
|
||||
\footahref{http://www.ejabberd.im/contributions}{contributed modules} on the
|
||||
\ejabberd{} website. Please remember that these contributions might not work or
|
||||
@@ -2742,7 +2810,6 @@ hosts in ejabberd.
|
||||
|
||||
Options:
|
||||
\begin{description}
|
||||
\dbtype
|
||||
\titem{\{access, AccessName\}} \ind{options!access}This option specifies who is allowed to
|
||||
send announcements and to set the message of the day (by default, nobody is
|
||||
able to send such messages).
|
||||
@@ -3073,7 +3140,6 @@ End user information:
|
||||
Options:
|
||||
\begin{description}
|
||||
\hostitem{irc}
|
||||
\dbtype
|
||||
\titem{\{access, AccessName\}} \ind{options!access}This option can be used to specify who
|
||||
may use the IRC transport (default value: \term{all}).
|
||||
\titem{\{default\_encoding, Encoding\}} \ind{options!defaultencoding}Set the default IRC encoding.
|
||||
@@ -3124,7 +3190,6 @@ connected user was last active on the server, or to query the uptime of the
|
||||
Options:
|
||||
\begin{description}
|
||||
\iqdiscitem{Last activity (\ns{jabber:iq:last})}
|
||||
\dbtype
|
||||
\end{description}
|
||||
|
||||
\makesubsection{modmuc}{\modmuc{}}
|
||||
@@ -3159,7 +3224,6 @@ on an available node on first connection attempt.
|
||||
Module options:
|
||||
\begin{description}
|
||||
\hostitem{conference}
|
||||
\dbtype
|
||||
\titem{\{access, AccessName\}} \ind{options!access}You can specify who is allowed to use
|
||||
the Multi-User Chat service. By default everyone is allowed to use it.
|
||||
\titem{\{access\_create, AccessName\}} \ind{options!access\_create}To configure who is
|
||||
@@ -3434,10 +3498,6 @@ Options:
|
||||
\term{html} stores in HTML format,
|
||||
\term{plaintext} stores in plain text.
|
||||
The default value is \term{html}.
|
||||
\titem{\{file\_permissions, \{Mode, Group\}\}}\ind{options!file\_permissions}
|
||||
Define the permissions that must be used when creating the log files:
|
||||
the number of the mode, and the numeric id of the group that will own the files.
|
||||
The default value is \term{\{644, 33\}}.
|
||||
\titem{\{outdir, Path\}}\ind{options!outdir}
|
||||
This option sets the full path to the directory in which the HTML files should
|
||||
be stored. Make sure the \ejabberd{} daemon user has write access on that
|
||||
@@ -3504,8 +3564,6 @@ Examples:
|
||||
{access_log, muc_log},
|
||||
{cssfile, false},
|
||||
{dirtype, subdirs},
|
||||
{dirtype, subdirs},
|
||||
{file_permissions, {644, 33}},
|
||||
{outdir, "/var/www/muclogs"},
|
||||
{timezone, local}
|
||||
]},
|
||||
@@ -3514,6 +3572,56 @@ Examples:
|
||||
\end{verbatim}
|
||||
\end{itemize}
|
||||
|
||||
\makesubsection{modmulticast}{\modmulticast{}}
|
||||
\ind{modules!\modmulticast{}}
|
||||
|
||||
This module implements Extended Stanza Addressing (\xepref{0033}).
|
||||
|
||||
\begin{description}
|
||||
\hostitem{multicast}
|
||||
\titem{\{access, AccessName\}}\ind{options!access}
|
||||
This option specifies the access rule that defines who can send packets to the multicast service.
|
||||
The default value is \term{all}.
|
||||
\titem{\{limits, [\{SenderType, StanzaType, Number\}]\}}\ind{options!limits}
|
||||
Specify a list of custom limits which override the default ones defined
|
||||
in (\xepref{0033}).
|
||||
Where:
|
||||
\begin{itemize}
|
||||
\item SenderType can have values: local or remote.
|
||||
\item StanzaType can have values: message or presence.
|
||||
\item Number can be a positive integer or the key word infinite.
|
||||
\end{itemize}
|
||||
The default value is \term{[]}.
|
||||
\end{description}
|
||||
|
||||
Example configuration:
|
||||
\begin{verbatim}
|
||||
%% Only admins can send packets to multicast service
|
||||
{access, multicast, [{allow, admin}, {deny, all}]}.
|
||||
|
||||
%% If you want to allow all your users:
|
||||
%%{access, multicast, [{allow, all}]}.
|
||||
|
||||
%% This allows both admins and remote users to send packets,
|
||||
%% but does not allow local users
|
||||
%%{acl, allservers, {server_glob, "*"}}.
|
||||
%%{access, multicast, [{allow, admin}, {deny, local}, {allow, allservers}]}.
|
||||
|
||||
{modules, [
|
||||
...
|
||||
{mod_multicast, [
|
||||
%%{host, "multicast.@HOST@"},
|
||||
{access, multicast},
|
||||
{limits, [
|
||||
{local, message, 40},
|
||||
{local, presence, infinite},
|
||||
{remote, message, 150}
|
||||
]}
|
||||
]},
|
||||
...
|
||||
]}.
|
||||
\end{verbatim}
|
||||
|
||||
\makesubsection{modoffline}{\modoffline{}}
|
||||
\ind{modules!\modoffline{}}
|
||||
|
||||
@@ -3525,7 +3633,6 @@ online again. Thus it is very similar to how email works. Note that
|
||||
(see section~\ref{ejabberdctl}).
|
||||
|
||||
\begin{description}
|
||||
\dbtype
|
||||
\titem{\{access\_max\_user\_messages, AccessName\}}\ind{options!access\_max\_user\_messages}
|
||||
This option defines which access rule will be enforced to limit
|
||||
the maximum number of offline messages that a user can have (quota).
|
||||
@@ -3656,7 +3763,6 @@ their \XMPP{} client, they will be able to:
|
||||
Options:
|
||||
\begin{description}
|
||||
\iqdiscitem{Blocking Communication (\ns{jabber:iq:privacy})}
|
||||
\dbtype
|
||||
\end{description}
|
||||
|
||||
\makesubsection{modprivate}{\modprivate{}}
|
||||
@@ -3673,7 +3779,6 @@ of client-specific preferences; another is Bookmark Storage (\xepref{0048}).
|
||||
Options:
|
||||
\begin{description}
|
||||
\iqdiscitem{Private XML Storage (\ns{jabber:iq:private})}
|
||||
\dbtype
|
||||
\end{description}
|
||||
|
||||
\makesubsection{modproxy}{\modproxy{}}
|
||||
@@ -4014,7 +4119,6 @@ It also supports Roster Versioning (\xepref{0237}).
|
||||
Options:
|
||||
\begin{description}
|
||||
\iqdiscitem{Roster Management (\ns{jabber:iq:roster})}
|
||||
\dbtype
|
||||
\titem{\{versioning, false|true\}} \ind{options!versioning}Enables
|
||||
Roster Versioning.
|
||||
This option is disabled by default.
|
||||
@@ -4025,7 +4129,7 @@ Options:
|
||||
This option does not affect the client in any way.
|
||||
This option is only useful if Roster Versioning is enabled.
|
||||
This option is disabled by default.
|
||||
Important: if you use \modsharedroster{} or \modsharedrosterldap{},
|
||||
Important: if you use \modsharedroster{}, \modsharedrosterodbc{} or \modsharedrosterldap{},
|
||||
you must disable this option.
|
||||
\end{description}
|
||||
|
||||
@@ -4092,11 +4196,6 @@ A shared roster group can have members from any XMPP server,
|
||||
but the presence will only be available from and to members
|
||||
of the same virtual host where the group is created.
|
||||
|
||||
Options:
|
||||
\begin{description}
|
||||
\dbtype
|
||||
\end{description}
|
||||
|
||||
Shared roster groups can be edited \emph{only} via the Web Admin. Each group
|
||||
has a unique identification and the following parameters:
|
||||
\begin{description}
|
||||
@@ -4615,7 +4714,6 @@ Options:
|
||||
\begin{description}
|
||||
\hostitem{vjud}
|
||||
\iqdiscitem{\ns{vcard-temp}}
|
||||
\dbtype
|
||||
\titem{\{search, true|false\}}\ind{options!search}This option specifies whether the search
|
||||
functionality is enabled or not
|
||||
If disabled, the option \term{host} will be ignored and the
|
||||
@@ -4631,7 +4729,7 @@ Options:
|
||||
\titem{\{search\_all\_hosts, true|false\}}\ind{options!search\_all\_hosts}If this option is set
|
||||
to \term{true}, search operations will apply to all virtual hosts. Otherwise
|
||||
only the current host will be searched. The default value is \term{true}.
|
||||
This option is available in \modvcard when using Mnesia, but not when using ODBC storage.
|
||||
This option is available in \modvcard, but not available in \modvcardodbc.
|
||||
\end{description}
|
||||
|
||||
Examples:
|
||||
@@ -4904,11 +5002,6 @@ presence stanza rewrite.
|
||||
For this reason, enabling this module will introduce a computational overhead
|
||||
in servers with clients that change frequently their presence.
|
||||
|
||||
Options:
|
||||
\begin{description}
|
||||
\dbtype
|
||||
\end{description}
|
||||
|
||||
\makesubsection{modversion}{\modversion{}}
|
||||
\ind{modules!\modversion{}}\ind{protocols!XEP-0092: Software Version}
|
||||
|
||||
@@ -4977,6 +5070,7 @@ In this example there is no restriction:
|
||||
\end{verbatim}
|
||||
|
||||
If account \term{robot1@example.org} is registered in \ejabberd{} with password \term{abcdef}
|
||||
(which MD5 is E8B501798950FC58AAD83C8C14978E),
|
||||
and \term{ejabberd.cfg} contains this setting:
|
||||
\begin{verbatim}
|
||||
{hosts, ["example.org"]}.
|
||||
@@ -4988,7 +5082,7 @@ then you can do this in the shell:
|
||||
\begin{verbatim}
|
||||
$ ejabberdctl registered_users example.org
|
||||
Error: no_auth_provided
|
||||
$ ejabberdctl --auth robot1 example.org abcdef registered_users example.org
|
||||
$ ejabberdctl --auth robot1 example.org E8B501798950FC58AAD83C8C14978E registered_users example.org
|
||||
robot1
|
||||
testuser1
|
||||
testuser2
|
||||
@@ -5091,9 +5185,10 @@ with a defined number and type of calling arguments and type of result
|
||||
that is registered in the \term{ejabberd\_commands} service.
|
||||
Those commands can be defined in any Erlang module and executed using any valid frontend.
|
||||
|
||||
\ejabberd{} includes a frontend to execute \term{ejabberd commands}: the script \term{ejabberdctl}.
|
||||
\ejabberd{} includes two frontends to execute \term{ejabberd commands}:
|
||||
the \term{ejabberdctl} shell script (see \ref{ejabberdctl})
|
||||
and the \term{ejabberd\_xmlrpc} XML-RPC listener (see \ref{listened-module}).
|
||||
Other known frontends that can be installed to execute ejabberd commands in different ways are:
|
||||
\term{ejabberd\_xmlrpc} (XML-RPC service),
|
||||
\term{mod\_rest} (HTTP POST service),
|
||||
\term{mod\_shcommands} (ejabberd WebAdmin page).
|
||||
|
||||
@@ -5151,8 +5246,8 @@ The most interesting ones are:
|
||||
from other Jabber/XMPP servers
|
||||
There exist tutorials to
|
||||
\footahref{http://www.ejabberd.im/migrate-to-ejabberd}{migrate from other software to ejabberd}.
|
||||
\titem{export2odbc virtualhost directory} \ind{export mnesia data to SQL files}
|
||||
Export virtual host information from Mnesia tables to SQL files.
|
||||
\titem{export\_odbc virtualhost filename} \ind{export mnesia data to a SQL file}
|
||||
Export virtual host information from Mnesia tables to a SQL file.
|
||||
\titem{delete\_expired\_messages} This option can be used to delete old messages
|
||||
in offline storage. This might be useful when the number of offline messages
|
||||
is very high.
|
||||
@@ -5183,6 +5278,7 @@ and is Username, Hostname and Password of a local XMPP account
|
||||
that has permission to execute the corresponding command.
|
||||
This means that the account must be registered in the local ejabberd,
|
||||
because the information will be verified.
|
||||
It is possible to provide the plaintext password or its MD5 sum.
|
||||
|
||||
When one or several access restrictions are defined and the
|
||||
authentication information is provided,
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
# Managing pubsub nodes through HTTP Atompub #
|
||||
|
||||
|
||||
## Configuration ##
|
||||
|
||||
These options will be used by the service to know how to build URLs. Using the previous configuration items the service should be accessed through `http://notify.push.bbc.co.uk:5280/pshb/<host>/<node>/`.
|
||||
|
||||
Also, in the ejabberd_http handler configuration, add the identified line.
|
||||
|
||||
{5280, ejabberd_http, [
|
||||
http_poll,
|
||||
web_admin,
|
||||
{request_handlers, [{["pshb"], pshb_http}]} % this should be added
|
||||
]}
|
||||
|
||||
It will automatically detect the version of mod_pubsub (odbc or mnesia) and call the appropriate module.
|
||||
|
||||
## Important notice ##
|
||||
|
||||
In the current version of the code, some security checks are not done :
|
||||
|
||||
* node creation uses the default `all` access_createnode acl, not checking for the actual configuration.
|
||||
|
||||
* most read operations are successfully executed without authentication. HOWEVER listing items can only be done when the node access_model is "open". In all other cases, the service returns 403. A finer grained authentication will be implemented.
|
||||
|
||||
|
||||
## Usage example with cURL ##
|
||||
|
||||
### Errors ###
|
||||
|
||||
HTTP status codes are used as intended. Additionally, the XMPP error stanza can also be set in the body :
|
||||
|
||||
$ curl -i -X POST -u cstar@localhost:encore -d @createnode.xml http://localhost:5280/pshb/localhost
|
||||
HTTP/1.1 409 Conflict
|
||||
Content-Type: text/html; charset=utf-8
|
||||
Content-Length: 95
|
||||
Content-type: application/xml
|
||||
|
||||
<error code='409' type='cancel'><conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></error>
|
||||
|
||||
or
|
||||
|
||||
$ curl -i -X DELETE -u cstar@localhost:encore http://localhost:5280/pshb/localhost/princely_musings
|
||||
HTTP/1.1 404 Not Found
|
||||
Content-Type: text/html; charset=utf-8
|
||||
Content-Length: 101
|
||||
Content-type: application/xml
|
||||
|
||||
<error code='404' type='cancel'><item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></error>
|
||||
|
||||
### Getting the service document ###
|
||||
|
||||
No authentication necessary. All nodes are listed.
|
||||
|
||||
$ curl -i http://host:port/pshb/domain/
|
||||
|
||||
### Getting items from a node ###
|
||||
|
||||
No authentication done, and all nodes are accessible.
|
||||
|
||||
$ curl -i http://host:port/pshb/domain/node/
|
||||
|
||||
|
||||
### Posting a new item ###
|
||||
|
||||
$ curl -u jid:password -i -X POST -d @entry.atom http://post:port/pshb/domain/node
|
||||
|
||||
User ability to post is based on node configuration.
|
||||
|
||||
### Editing a new item ###
|
||||
|
||||
$ curl -u jid:password -i -X POST -d @entry.atom http://post:port/pshb/domain/node/itemid
|
||||
|
||||
User ability to post is based on node configuration.
|
||||
|
||||
### Deleting an item ###
|
||||
|
||||
$ curl -u jid:password -i -X DELETE http://post:port/pshb/domain/node/itemid
|
||||
|
||||
User ability to post is based on node configuration.
|
||||
|
||||
|
||||
### Creating a new node ###
|
||||
|
||||
An instant node can be created if server configuration allows:
|
||||
|
||||
$ curl -X POST -u cstar@localhost:encore -d "" http://localhost:5280/pshb/localhost
|
||||
|
||||
or
|
||||
|
||||
$ curl -X POST -u cstar@localhost:encore -d "<pubsub><create node='princely_musings'/></pubsub>" http://localhost:5280/pshb/localhost
|
||||
|
||||
configure element (as per XEP-60) can be passed in the pubsub body.
|
||||
|
||||
$ cat createnode.xml
|
||||
<pubsub><create node='princely_musings' type='flat'/>
|
||||
<x xmlns='jabber:x:data' type='submit'>
|
||||
<field var='FORM_TYPE' type='hidden'>
|
||||
<value>http://jabber.org/protocol/pubsub#node_config</value>
|
||||
</field>
|
||||
<field var='pubsub#title'><value>Princely Musings (Atom)</value></field>
|
||||
<field var='pubsub#max_payload_size'><value>1028</value></field>
|
||||
<field var='pubsub#type'><value>Atom</value></field>
|
||||
</x>
|
||||
</pubsub>
|
||||
|
||||
$ curl -i -X POST -u cstar@localhost:encore -d @createnode.xml http://localhost:5280/pshb/localhost
|
||||
HTTP/1.1 200 OK
|
||||
Content-Length: 130
|
||||
Content-Type: application/xml
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?><pubsub xmlns='http://jabber.org/protocol/pubsub'><create node='princely_musings'/></pubsub>
|
||||
|
||||
### Editing a node configuration ###
|
||||
|
||||
$ cat editnode.xml
|
||||
<pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
|
||||
<configure node='princely_musings'>
|
||||
<x xmlns='jabber:x:data' type='submit'>
|
||||
<field var='FORM_TYPE' type='hidden'>
|
||||
<value>http://jabber.org/protocol/pubsub#node_config</value>
|
||||
</field>
|
||||
<field var='pubsub#title'><value>Princely Musings (Atom)</value></field>
|
||||
<field var='pubsub#deliver_notifications'><value>1</value></field>
|
||||
<field var='pubsub#deliver_payloads'><value>1</value></field>
|
||||
<field var='pubsub#persist_items'><value>1</value></field>
|
||||
<field var='pubsub#max_items'><value>10</value></field>
|
||||
<field var='pubsub#item_expire'><value>604800</value></field>
|
||||
<field var='pubsub#access_model'><value>roster</value></field>
|
||||
</x>
|
||||
</configure>
|
||||
</pubsub>
|
||||
|
||||
|
||||
$ curl -i -X PUT -u cstar@localhost:encore -d @createnode.xml http://localhost:5280/pshb/localhost/princely_musings
|
||||
|
||||
|
||||
|
||||
### Deleting a node ###
|
||||
|
||||
A node is deleted by:
|
||||
|
||||
$ curl -X DELETE -u cstar@localhost:encore http://localhost:5280/pshb/localhost/princely_musings
|
||||
|
||||
|
||||
|
||||
Executable
+99
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env escript
|
||||
%% -*- erlang -*-
|
||||
|
||||
-record(cmd, {name, desc, longdesc, args, result}).
|
||||
|
||||
main(_) ->
|
||||
Dir = filename:absname(filename:join(["..", "src"])),
|
||||
FileIn = filename:join([Dir, "mod_admin_p1.erl"]),
|
||||
{ok, Forms1} = epp_dodger:parse_file(FileIn, [no_fail]),
|
||||
Comments = erl_comment_scan:file(FileIn),
|
||||
Forms = erl_recomment:recomment_forms(Forms1, Comments),
|
||||
Tree = erl_syntax:flatten_form_list(Forms),
|
||||
AuxFile = "mod_admin.tex",
|
||||
case file:open(AuxFile, [write]) of
|
||||
{ok, Fd} ->
|
||||
io:format(Fd, "\\newcommand{\\modadminsection}{\\begin{description}~n", []),
|
||||
process(Fd, Tree),
|
||||
io:format(Fd, "\\end{description}}~n", []),
|
||||
file:close(Fd),
|
||||
halt(0);
|
||||
{error, Why} ->
|
||||
io:format("failed to open file ~s: ~s",
|
||||
[AuxFile, file:format_error(Why)]),
|
||||
halt(1)
|
||||
end.
|
||||
|
||||
process(Fd, Tree) ->
|
||||
case erl_syntax:type(Tree) of
|
||||
record_expr ->
|
||||
case erl_syntax_lib:analyze_record_expr(Tree) of
|
||||
{record_expr, {ejabberd_commands, _}} ->
|
||||
Fs = erl_syntax:record_expr_fields(Tree),
|
||||
Cmd = lists:foldl(
|
||||
fun(F, C) ->
|
||||
Name = erl_syntax:record_field_name(F),
|
||||
Value = erl_syntax:record_field_value(F),
|
||||
case {erl_syntax:concrete(Name),
|
||||
catch erl_syntax:concrete(Value)} of
|
||||
{_, {'EXIT', _}} ->
|
||||
C;
|
||||
{name, V} ->
|
||||
C#cmd{name = V};
|
||||
{desc, V} ->
|
||||
C#cmd{desc = V};
|
||||
{longdesc, V} ->
|
||||
C#cmd{longdesc = V};
|
||||
{args, V} ->
|
||||
C#cmd{args = V};
|
||||
{result, V} ->
|
||||
C#cmd{result = V};
|
||||
_ ->
|
||||
C
|
||||
end
|
||||
end, #cmd{}, Fs),
|
||||
format_command(Fd, Cmd);
|
||||
_ ->
|
||||
ok
|
||||
end;
|
||||
_ ->
|
||||
case erl_syntax:subtrees(Tree) of
|
||||
[] ->
|
||||
ok;
|
||||
List ->
|
||||
lists:foreach(
|
||||
fun(Group) ->
|
||||
lists:foreach(
|
||||
fun(Subtree) ->
|
||||
process(Fd, Subtree)
|
||||
end, Group)
|
||||
end, List)
|
||||
end
|
||||
end.
|
||||
|
||||
-define(B(S), S).
|
||||
|
||||
format_command(Fd, #cmd{name = Cmd,
|
||||
desc = Desc,
|
||||
longdesc = _LongDesc,
|
||||
args = ArgsDef,
|
||||
result = _ResultDef}) ->
|
||||
io:format(Fd, "\\titem{~s ~s} ~s~n",
|
||||
[escape_underscores(atom_to_list(Cmd)),
|
||||
flatten_arguments(ArgsDef),
|
||||
escape_underscores(Desc)]).
|
||||
|
||||
flatten_arguments(Args) ->
|
||||
string:join(
|
||||
lists:map(
|
||||
fun({Name, _Type}) ->
|
||||
escape_underscores(io_lib:format("~s", [Name]))
|
||||
end, Args),
|
||||
" ").
|
||||
|
||||
escape_underscores(S) ->
|
||||
lists:flatten(
|
||||
[case C of
|
||||
$_ -> "\\_";
|
||||
_ -> C
|
||||
end || C <- S]).
|
||||
@@ -1,67 +0,0 @@
|
||||
|
||||
Release Notes
|
||||
ejabberd 2.1.12
|
||||
|
||||
ejabberd 2.1.12 includes a many bugfixes and a few improvements.
|
||||
|
||||
Read more details about the changes in:
|
||||
http://redir.process-one.net/ejabberd-2.1.12
|
||||
|
||||
Download the source code and installers from:
|
||||
http://www.process-one.net/en/ejabberd/
|
||||
|
||||
|
||||
The changes are:
|
||||
|
||||
* Core ejabberd
|
||||
- Make terms serialization faster
|
||||
- Reduce size of XML stream state
|
||||
|
||||
* Administration
|
||||
- Add SCRAM and remove MD5 support to ejabberd commands auth verification
|
||||
- Added command to list all the vhosts registered in an ejabberd node
|
||||
- Added export2odbc command, copied from mod_admin_extra.erl
|
||||
- Fix ejabberdctl number of arguments error report with R15
|
||||
- Check node name is available before starting ejabberd (EJAB-1572)
|
||||
- Fix ejabberd_xmlrpc commands authentication with SCRAM
|
||||
- Fix mod_offline:store_offline_msg argument (EJAB-1581)
|
||||
- Log IP address when auth attempt fails
|
||||
- Make sure update_info returns atoms only (EJAB-1595)
|
||||
- On shutdown, first stop listeners, then modules
|
||||
|
||||
* Encryption
|
||||
- Detect OpenSSL version at runtime, not at compile time
|
||||
- Fixed signedness issue in tls_drv GET_DESCRYPTED_INPUT (EJAB-1591)
|
||||
- Enable DHE key exchange in TLS driver
|
||||
- Enable ECDHE key exchange in TSL driver
|
||||
- Disable old and unsecure ciphers in TLS driver
|
||||
- Disable SSL 2.0 in TLS driver
|
||||
|
||||
* HTTP-Bind
|
||||
- Do not trigger item-not-found errors in mod_http_bind
|
||||
- Repeated http-bind request should abort only requests with same rid
|
||||
- Receiving missing request shouldn't close waiting out-ouf-order request
|
||||
|
||||
* XMPP
|
||||
- Allow multiple fqdn values in configuration (EJAB-1578)
|
||||
- Fix get_subscription_lists/4
|
||||
- Fix account registration
|
||||
- Send announce Message stanzas as Headline type instead of Normal
|
||||
|
||||
* Other
|
||||
- Guide: Fix file name of Name Service Switch
|
||||
- Guide: Document the db_type modules option (EJAB-1560)
|
||||
- LDAP: Fix broken JPEG photo (EJAB-1526)
|
||||
- LDAP: Fix compatibility with Erlang R16A (EJAB-1612)
|
||||
- MUC: Fix angle brackets handle in plaintext log (EJAB-1610)
|
||||
- MUC: Fix MUC start when Mnesia tables don't exist yet
|
||||
- MUC: New mod_muc_log option file_permissions (EJAB-1588)
|
||||
- ODBC: Merge SQL and Mnesia code into one module (EJAB-1560)
|
||||
- Translation: New Hebrew
|
||||
- Translation: Update Slovak
|
||||
|
||||
|
||||
Bug reports
|
||||
|
||||
You can officially report bugs on ProcessOne support site:
|
||||
http://support.process-one.net/
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
% ejabberd version (automatically generated).
|
||||
\newcommand{\version}{13.03-beta1}
|
||||
\newcommand{\version}{3.0.0}
|
||||
|
||||
@@ -154,6 +154,13 @@
|
||||
%%
|
||||
%%{{3478, udp}, ejabberd_stun, []},
|
||||
|
||||
%%
|
||||
%% To handle XML-RPC requests that provide admin credentials:
|
||||
%%
|
||||
%%{4560, ejabberd_xmlrpc, [
|
||||
%% {access_commands, [{admin, all, []}]}
|
||||
%% ]},
|
||||
|
||||
{5280, ejabberd_http, [
|
||||
%%{request_handlers,
|
||||
%% [
|
||||
Regular → Executable
+119
-96
@@ -7,12 +7,14 @@ ERL_MAX_PORTS=32000
|
||||
ERL_PROCESSES=250000
|
||||
ERL_MAX_ETS_TABLES=1400
|
||||
|
||||
SCRIPT_DIR=$(cd ${0%/*} && pwd)
|
||||
|
||||
# define default environment variables
|
||||
NODE=ejabberd
|
||||
HOST=localhost
|
||||
ERLANG_NODE=$NODE@$HOST
|
||||
ERL=@erl@
|
||||
INSTALLUSER=@installuser@
|
||||
ERL={{erl}}
|
||||
INSTALLUSER={{installuser}}
|
||||
|
||||
# parse command line parameters
|
||||
ARGS=
|
||||
@@ -33,7 +35,7 @@ done
|
||||
|
||||
# Define ejabberd variable if they have not been defined from the command line
|
||||
if [ "$ETCDIR" = "" ] ; then
|
||||
ETCDIR=@SYSCONFDIR@/ejabberd
|
||||
ETCDIR={{sysconfdir}}/ejabberd
|
||||
fi
|
||||
if [ "$EJABBERD_CONFIG_PATH" = "" ] ; then
|
||||
EJABBERD_CONFIG_PATH=$ETCDIR/ejabberd.cfg
|
||||
@@ -41,15 +43,17 @@ fi
|
||||
if [ "$EJABBERDCTL_CONFIG_PATH" = "" ] ; then
|
||||
EJABBERDCTL_CONFIG_PATH=$ETCDIR/ejabberdctl.cfg
|
||||
fi
|
||||
[ -f "$EJABBERDCTL_CONFIG_PATH" ] && . "$EJABBERDCTL_CONFIG_PATH"
|
||||
if [ -f "$EJABBERDCTL_CONFIG_PATH" ] ; then
|
||||
. "$EJABBERDCTL_CONFIG_PATH"
|
||||
fi
|
||||
if [ "$LOGS_DIR" = "" ] ; then
|
||||
LOGS_DIR=@LOCALSTATEDIR@/log/ejabberd
|
||||
LOGS_DIR={{localstatedir}}/log/ejabberd
|
||||
fi
|
||||
if [ "$SPOOLDIR" = "" ] ; then
|
||||
SPOOLDIR=@LOCALSTATEDIR@/lib/ejabberd
|
||||
SPOOLDIR={{localstatedir}}/lib/ejabberd
|
||||
fi
|
||||
if [ "$EJABBERD_DOC_PATH" = "" ] ; then
|
||||
EJABBERD_DOC_PATH=@DOCDIR@
|
||||
EJABBERD_DOC_PATH={{docdir}}
|
||||
fi
|
||||
if [ "$ERLANG_NODE_ARG" != "" ] ; then
|
||||
ERLANG_NODE=$ERLANG_NODE_ARG
|
||||
@@ -63,19 +67,21 @@ EJID=`id -g $INSTALLUSER`
|
||||
EXEC_CMD="false"
|
||||
for GID in $GIDS; do
|
||||
if [ $GID -eq 0 ] ; then
|
||||
EXEC_CMD="su ${INSTALLUSER} -p -c"
|
||||
EXEC_CMD="su ${INSTALLUSER} -p -c"
|
||||
fi
|
||||
done
|
||||
if [ "$ID" -eq "$EJID" ] ; then
|
||||
EXEC_CMD="sh -c"
|
||||
EXEC_CMD="sh -c"
|
||||
fi
|
||||
if [ "$EXEC_CMD" = "false" ] ; then
|
||||
echo "This command can only be run by root or the user $INSTALLUSER" >&2
|
||||
exit 4
|
||||
echo "This command can only be run by root or the user $INSTALLUSER" >&2
|
||||
exit 4
|
||||
fi
|
||||
|
||||
NAME=-name
|
||||
[ "$ERLANG_NODE" = "${ERLANG_NODE%.*}" ] && NAME=-sname
|
||||
if [ "$ERLANG_NODE" = "${ERLANG_NODE%.*}" ] ; then
|
||||
NAME=-sname
|
||||
fi
|
||||
|
||||
KERNEL_OPTS=""
|
||||
if [ "$FIREWALL_WINDOW" != "" ] ; then
|
||||
@@ -88,23 +94,25 @@ fi
|
||||
ERLANG_OPTS="+K $POLL -smp $SMP +P $ERL_PROCESSES $ERL_OPTIONS"
|
||||
|
||||
# define additional environment variables
|
||||
if [ "$EJABBERDDIR" = "" ]; then
|
||||
EJABBERDDIR=@LIBDIR@/ejabberd
|
||||
fi
|
||||
if [ "$EJABBERD_EBIN_PATH" = "" ]; then
|
||||
EJABBERD_EBIN_PATH=$EJABBERDDIR/ebin
|
||||
fi
|
||||
if [ "$EJABBERD_PRIV_PATH" = "" ]; then
|
||||
EJABBERD_PRIV_PATH=$EJABBERDDIR/priv
|
||||
fi
|
||||
if [ "$EJABBERD_BIN_PATH" = "" ]; then
|
||||
EJABBERD_BIN_PATH=$EJABBERD_PRIV_PATH/bin
|
||||
fi
|
||||
if [ "$EJABBERD_SO_PATH" = "" ]; then
|
||||
EJABBERD_SO_PATH=$EJABBERD_PRIV_PATH/lib
|
||||
fi
|
||||
if [ "$EJABBERD_MSGS_PATH" = "" ]; then
|
||||
EJABBERD_MSGS_PATH=$EJABBERD_PRIV_PATH/msgs
|
||||
if [ "{{release}}" != "true" ] ; then
|
||||
if [ "$EJABBERDDIR" = "" ] ; then
|
||||
EJABBERDDIR={{libdir}}/ejabberd
|
||||
fi
|
||||
if [ "$EJABBERD_EBIN_PATH" = "" ] ; then
|
||||
EJABBERD_EBIN_PATH=$EJABBERDDIR/ebin
|
||||
fi
|
||||
if [ "$EJABBERD_PRIV_PATH" = "" ] ; then
|
||||
EJABBERD_PRIV_PATH=$EJABBERDDIR/priv
|
||||
fi
|
||||
if [ "$EJABBERD_BIN_PATH" = "" ] ; then
|
||||
EJABBERD_BIN_PATH=$EJABBERD_PRIV_PATH/bin
|
||||
fi
|
||||
if [ "$EJABBERD_SO_PATH" = "" ] ; then
|
||||
EJABBERD_SO_PATH=$EJABBERD_PRIV_PATH/lib
|
||||
fi
|
||||
if [ "$EJABBERD_MSGS_PATH" = "" ] ; then
|
||||
EJABBERD_MSGS_PATH=$EJABBERD_PRIV_PATH/msgs
|
||||
fi
|
||||
fi
|
||||
|
||||
EJABBERD_LOG_PATH=$LOGS_DIR/ejabberd.log
|
||||
@@ -144,9 +152,7 @@ export EXEC_CMD
|
||||
# start server
|
||||
start ()
|
||||
{
|
||||
checknodenameusage
|
||||
[ "$?" -eq 0 ] && echo "\nERROR: The node '$ERLANG_NODE' is already running." && return 1
|
||||
|
||||
check_start
|
||||
$EXEC_CMD "$ERL \
|
||||
$NAME $ERLANG_NODE \
|
||||
-noinput -detached \
|
||||
@@ -178,7 +184,7 @@ debug ()
|
||||
echo " EJABBERD_BYPASS_WARNINGS=true"
|
||||
echo "Press any key to continue"
|
||||
if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then
|
||||
read foo
|
||||
read foo
|
||||
fi
|
||||
echo ""
|
||||
TTY=`tty | sed -e 's/.*\///g'`
|
||||
@@ -193,9 +199,7 @@ debug ()
|
||||
# start interactive server
|
||||
live ()
|
||||
{
|
||||
checknodenameusage
|
||||
[ "$?" -eq 0 ] && echo "\nERROR: The node '$ERLANG_NODE' is already running." && return 1
|
||||
|
||||
check_start
|
||||
echo "--------------------------------------------------------------------"
|
||||
echo ""
|
||||
echo "IMPORTANT: ejabberd is going to start in LIVE (interactive) mode."
|
||||
@@ -212,7 +216,7 @@ live ()
|
||||
echo " EJABBERD_BYPASS_WARNINGS=true"
|
||||
echo "Press any key to continue"
|
||||
if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then
|
||||
read foo
|
||||
read foo
|
||||
fi
|
||||
echo ""
|
||||
$EXEC_CMD "$ERL \
|
||||
@@ -224,6 +228,13 @@ live ()
|
||||
$ERLANG_OPTS $ARGS \"$@\""
|
||||
}
|
||||
|
||||
etop()
|
||||
{
|
||||
$EXEC_CMD "$ERL \
|
||||
$NAME debug-${TTY}-${ERLANG_NODE} \
|
||||
-hidden -s etop -s erlang halt -output text -node $ERLANG_NODE"
|
||||
}
|
||||
|
||||
help ()
|
||||
{
|
||||
echo ""
|
||||
@@ -251,69 +262,69 @@ ctl ()
|
||||
# using flock if available. Expects a linux-style
|
||||
# flock that can lock a file descriptor.
|
||||
MAXCONNID=100
|
||||
CONNLOCKDIR=@LOCALSTATEDIR@/lock/ejabberdctl
|
||||
CONNLOCKDIR={{localstatedir}}/lock/ejabberdctl
|
||||
FLOCK='/usr/bin/flock'
|
||||
if [ ! -x "$FLOCK" ] || [ ! -d "$CONNLOCKDIR" ] ; then
|
||||
JOT='/usr/bin/jot'
|
||||
if [ ! -x "$JOT" ] ; then
|
||||
# no flock or jot, simply invoke ctlexec()
|
||||
CTL_CONN="ctl-${ERLANG_NODE}"
|
||||
ctlexec $CTL_CONN $COMMAND
|
||||
result=$?
|
||||
else
|
||||
# no flock, but at least there is jot
|
||||
RAND=`jot -r 1 0 $MAXCONNID`
|
||||
CTL_CONN="ctl-${RAND}-${ERLANG_NODE}"
|
||||
ctlexec $CTL_CONN $COMMAND
|
||||
result=$?
|
||||
fi
|
||||
JOT='/usr/bin/jot'
|
||||
if [ ! -x "$JOT" ] ; then
|
||||
# no flock or jot, simply invoke ctlexec()
|
||||
CTL_CONN="ctl-${ERLANG_NODE}"
|
||||
ctlexec $CTL_CONN $COMMAND
|
||||
result=$?
|
||||
else
|
||||
# no flock, but at least there is jot
|
||||
RAND=`jot -r 1 0 $MAXCONNID`
|
||||
CTL_CONN="ctl-${RAND}-${ERLANG_NODE}"
|
||||
ctlexec $CTL_CONN $COMMAND
|
||||
result=$?
|
||||
fi
|
||||
else
|
||||
# we have flock so we get a lock
|
||||
# on one of a limited number of
|
||||
# conn names -- this allows
|
||||
# concurrent invocations using a bound
|
||||
# number of atoms
|
||||
for N in $(seq 1 $MAXCONNID); do
|
||||
CTL_CONN="ejabberdctl-$N"
|
||||
CTL_LOCKFILE="$CONNLOCKDIR/$CTL_CONN"
|
||||
(
|
||||
exec 8>"$CTL_LOCKFILE"
|
||||
if flock --nb 8; then
|
||||
ctlexec $CTL_CONN $COMMAND
|
||||
# we have flock so we get a lock
|
||||
# on one of a limited number of
|
||||
# conn names -- this allows
|
||||
# concurrent invocations using a bound
|
||||
# number of atoms
|
||||
for N in $(seq 1 $MAXCONNID); do
|
||||
CTL_CONN="ejabberdctl-$N"
|
||||
CTL_LOCKFILE="$CONNLOCKDIR/$CTL_CONN"
|
||||
(
|
||||
exec 8>"$CTL_LOCKFILE"
|
||||
if flock --nb 8; then
|
||||
ctlexec $CTL_CONN $COMMAND
|
||||
ssresult=$?
|
||||
# segregate from possible flock exit(1)
|
||||
ssresult=$(expr $ssresult \* 10)
|
||||
exit $ssresult
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
ssresult=$(expr $ssresult \* 10)
|
||||
exit $ssresult
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
)
|
||||
result=$?
|
||||
if [ $result -eq 1 ]; then
|
||||
result=$?
|
||||
if [ $result -eq 1 ] ; then
|
||||
# means we errored out in flock
|
||||
# rather than in the exec - stay in the loop
|
||||
# trying other conn names...
|
||||
badlock=1
|
||||
else
|
||||
badlock=""
|
||||
break;
|
||||
fi
|
||||
done
|
||||
result=$(expr $result / 10)
|
||||
badlock=1
|
||||
else
|
||||
badlock=""
|
||||
break;
|
||||
fi
|
||||
done
|
||||
result=$(expr $result / 10)
|
||||
fi
|
||||
|
||||
if [ "$badlock" ];then
|
||||
echo "Ran out of connections to try. Your ejabberd processes" >&2
|
||||
echo "may be stuck or this is a very busy server. For very" >&2
|
||||
echo "busy servers, consider raising MAXCONNID in ejabberdctl">&2
|
||||
exit 1;
|
||||
if [ "$badlock" ] ;then
|
||||
echo "Ran out of connections to try. Your ejabberd processes" >&2
|
||||
echo "may be stuck or this is a very busy server. For very" >&2
|
||||
echo "busy servers, consider raising MAXCONNID in ejabberdctl">&2
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
case $result in
|
||||
0) :;;
|
||||
1) :;;
|
||||
2) help;;
|
||||
3) help;;
|
||||
0) :;;
|
||||
1) :;;
|
||||
2) help;;
|
||||
3) help;;
|
||||
esac
|
||||
return $result
|
||||
}
|
||||
@@ -344,6 +355,26 @@ stop_epmd()
|
||||
epmd -names | grep -q name || epmd -kill
|
||||
}
|
||||
|
||||
# make sure node not already running and node name unregistered
|
||||
check_start()
|
||||
{
|
||||
epmd -names | grep -q $NODE && {
|
||||
ps ux | grep -v grep | grep -q $ERLANG_NODE && {
|
||||
echo "ERROR: The ejabberd node '$ERLANG_NODE' is already running."
|
||||
exit 4
|
||||
} || {
|
||||
ps ux | grep beam | grep -v "grep beam" && {
|
||||
echo "ERROR: The ejabberd node '$ERLANG_NODE' is registered,"
|
||||
echo " but no ejabberd process has been found."
|
||||
echo "Shutdown other erlang nodes, and call 'epmd -kill'."
|
||||
exit 5
|
||||
} || {
|
||||
epmd -kill
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# allow sync calls
|
||||
wait_for_status()
|
||||
{
|
||||
@@ -351,7 +382,7 @@ wait_for_status()
|
||||
# return: 0 OK, 1 KO
|
||||
timeout=$2
|
||||
status=4
|
||||
while [ $status -ne $1 ]; do
|
||||
while [ $status -ne $1 ] ; do
|
||||
sleep $3
|
||||
timeout=$(($timeout - 1))
|
||||
[ $timeout -eq 0 ] && {
|
||||
@@ -369,19 +400,11 @@ wait_for_status()
|
||||
return $status
|
||||
}
|
||||
|
||||
# check node name is used or not
|
||||
# $? --> 0=alreadyused 1=available
|
||||
checknodenameusage ()
|
||||
{
|
||||
$EXEC_CMD "$ERL \
|
||||
$NAME $ERLANG_NODE \
|
||||
-s erlang halt | grep -c duplicate_name > /dev/null "
|
||||
}
|
||||
|
||||
case $ARGS in
|
||||
' start') start;;
|
||||
' debug') debug;;
|
||||
' live') live;;
|
||||
' etop') etop;;
|
||||
' started') wait_for_status 0 30 2;; # wait 30x2s before timeout
|
||||
' stopped') wait_for_status 3 15 2; stop_epmd;; # wait 15x2s before timeout
|
||||
*) ctl $ARGS;;
|
||||
@@ -0,0 +1,52 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
%%% published by the Free Software Foundation; either version 2 of the
|
||||
%%% License, or (at your option) any later version.
|
||||
%%%
|
||||
%%% This program is distributed in the hope that it will be useful,
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
%%% General Public License for more details.
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with this program; if not, write to the Free Software
|
||||
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
%%% 02111-1307 USA
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-define(CT_XML,
|
||||
{<<"Content-Type">>, <<"text/xml; charset=utf-8">>}).
|
||||
|
||||
-define(CT_PLAIN,
|
||||
{<<"Content-Type">>, <<"text/plain">>}).
|
||||
|
||||
-define(CT_JSON,
|
||||
{<<"Content-Type">>, <<"application/json">>}).
|
||||
|
||||
-define(AC_ALLOW_ORIGIN,
|
||||
{<<"Access-Control-Allow-Origin">>, <<"*">>}).
|
||||
|
||||
-define(AC_ALLOW_METHODS,
|
||||
{<<"Access-Control-Allow-Methods">>,
|
||||
<<"GET, POST, OPTIONS">>}).
|
||||
|
||||
-define(AC_ALLOW_HEADERS,
|
||||
{<<"Access-Control-Allow-Headers">>,
|
||||
<<"Content-Type">>}).
|
||||
|
||||
-define(AC_MAX_AGE,
|
||||
{<<"Access-Control-Max-Age">>, <<"86400">>}).
|
||||
|
||||
-define(OPTIONS_HEADER,
|
||||
[?CT_PLAIN, ?AC_ALLOW_ORIGIN, ?AC_ALLOW_METHODS,
|
||||
?AC_ALLOW_HEADERS, ?AC_MAX_AGE]).
|
||||
|
||||
-define(HEADER(CType),
|
||||
[CType, ?AC_ALLOW_ORIGIN, ?AC_ALLOW_HEADERS]).
|
||||
|
||||
-define(PROCNAME, ejabberd_mod_bosh).
|
||||
@@ -19,8 +19,6 @@
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
%% This macro returns a string of the ejabberd version running, e.g. "2.3.4"
|
||||
%% If the ejabberd application description isn't loaded, returns atom: undefined
|
||||
-define(VERSION, ejabberd_config:get_version()).
|
||||
|
||||
-define(MYHOSTS, ejabberd_config:get_myhosts()).
|
||||
@@ -29,13 +27,24 @@
|
||||
|
||||
-define(MYLANG, ejabberd_config:get_mylang()).
|
||||
|
||||
-define(MSGS_DIR, <<"msgs">>).
|
||||
-define(MSGS_DIR, filename:join(["priv", "msgs"])).
|
||||
|
||||
-define(CONFIG_PATH, <<"ejabberd.cfg">>).
|
||||
|
||||
-define(LOG_PATH, <<"ejabberd.log">>).
|
||||
|
||||
-define(EJABBERD_URI, <<"http://www.process-one.net/en/ejabberd/">>).
|
||||
-ifdef(ENABLE_FLASH_HACK).
|
||||
|
||||
-define(FLASH_HACK, true).
|
||||
|
||||
-else.
|
||||
|
||||
-define(FLASH_HACK, false).
|
||||
|
||||
-endif.
|
||||
|
||||
-define(EJABBERD_URI,
|
||||
<<"http://www.process-one.net/en/ejabberd/">>).
|
||||
|
||||
-define(S2STIMEOUT, 600000).
|
||||
|
||||
@@ -50,28 +59,3 @@
|
||||
-type scram() :: #scram{}.
|
||||
|
||||
-define(SCRAM_DEFAULT_ITERATION_COUNT, 4096).
|
||||
|
||||
%% ---------------------------------
|
||||
%% Logging mechanism
|
||||
|
||||
%% Print in standard output
|
||||
-define(PRINT(Format, Args), io:format(Format, Args)).
|
||||
|
||||
-define(DEBUG(Format, Args),
|
||||
ejabberd_logger:debug_msg(?MODULE, ?LINE, Format,
|
||||
Args)).
|
||||
|
||||
-define(INFO_MSG(Format, Args),
|
||||
ejabberd_logger:info_msg(?MODULE, ?LINE, Format, Args)).
|
||||
|
||||
-define(WARNING_MSG(Format, Args),
|
||||
ejabberd_logger:warning_msg(?MODULE, ?LINE, Format,
|
||||
Args)).
|
||||
|
||||
-define(ERROR_MSG(Format, Args),
|
||||
ejabberd_logger:error_msg(?MODULE, ?LINE, Format,
|
||||
Args)).
|
||||
|
||||
-define(CRITICAL_MSG(Format, Args),
|
||||
ejabberd_logger:critical_msg(?MODULE, ?LINE, Format,
|
||||
Args)).
|
||||
@@ -0,0 +1,93 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
%%% published by the Free Software Foundation; either version 2 of the
|
||||
%%% License, or (at your option) any later version.
|
||||
%%%
|
||||
%%% This program is distributed in the hope that it will be useful,
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
%%% General Public License for more details.
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with this program; if not, write to the Free Software
|
||||
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
%%% 02111-1307 USA
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-ifndef(mod_privacy_hrl).
|
||||
|
||||
-include("mod_privacy.hrl").
|
||||
|
||||
-endif.
|
||||
|
||||
%-define(SETS, gb_sets).
|
||||
-define(SETS, ejabberd_sets).
|
||||
|
||||
-define(DICT, dict).
|
||||
|
||||
-record(state,
|
||||
{socket,
|
||||
sockmod = ejabberd_socket :: ejabberd_socket | ejabberd_frontend_socket,
|
||||
socket_monitor = make_ref() :: reference(),
|
||||
xml_socket = false :: boolean(),
|
||||
streamid = <<"">> :: binary(),
|
||||
sasl_state :: any(),
|
||||
access :: atom(),
|
||||
shaper = none :: shaper:shaper(),
|
||||
zlib = false :: boolean(),
|
||||
tls = false :: boolean(),
|
||||
tls_required = false :: boolean(),
|
||||
tls_enabled = false :: boolean(),
|
||||
tls_options = [] :: list(),
|
||||
authenticated = false :: boolean() | replaced | rebinded,
|
||||
jid = #jid{} :: jid(),
|
||||
user = <<"">> :: binary(),
|
||||
server = ?MYNAME :: binary(),
|
||||
resource = <<"">> :: binary(),
|
||||
sid = {now(), self()} :: ejabberd_sm:sid(),
|
||||
pres_t = (?SETS):new() :: ?SETS:ej_set() | {pres_t, non_neg_integer()},
|
||||
pres_f = (?SETS):new() :: ?SETS:ej_set() | {pres_f, non_neg_integer()},
|
||||
pres_a = (?SETS):new() :: ?SETS:ej_set() | {pres_a, non_neg_integer()},
|
||||
pres_last :: xmlel(),
|
||||
pres_timestamp :: calendar:datetime(),
|
||||
privacy_list = #userlist{} :: userlist(),
|
||||
conn = unknown :: atom(),
|
||||
auth_module = unknown :: atom(),
|
||||
ip :: {inet:ip_address(), inet:port_number()},
|
||||
redirect = false :: boolean(),
|
||||
aux_fields = [] :: [{atom(), any()}],
|
||||
fsm_limit_opts = [] :: [{atom(), any()}],
|
||||
lang = ?MYLANG :: binary(),
|
||||
debug = false :: boolean(),
|
||||
flash_hack = false :: boolean(),
|
||||
flash_connection = false :: boolean(),
|
||||
reception = true :: boolean(),
|
||||
standby = false :: boolean(),
|
||||
queue = queue:new() :: queue(),
|
||||
queue_len = 0 :: integer(),
|
||||
pres_queue = gb_trees:empty() :: gb_tree(),
|
||||
keepalive_timer :: reference(),
|
||||
keepalive_timeout :: timeout(),
|
||||
oor_timeout :: timeout(),
|
||||
oor_status = <<"">> :: binary(),
|
||||
oor_show = <<"">> :: binary(),
|
||||
oor_notification :: xmlel(),
|
||||
oor_send_body = all :: first_per_user | first | all | none,
|
||||
oor_send_groupchat = false :: boolean(),
|
||||
oor_send_from = jid :: jid | username | name | none,
|
||||
oor_appid = <<"">> :: binary(),
|
||||
oor_unread = 0 :: integer(),
|
||||
oor_unread_users = (?SETS):new() :: ?SETS:ej_set(),
|
||||
oor_unread_client = 0 :: integer(),
|
||||
oor_offline = false :: boolean(),
|
||||
ack_enabled = false :: boolean(),
|
||||
ack_counter = 0 :: integer(),
|
||||
ack_queue = queue:new() :: queue(),
|
||||
ack_timer :: reference()}).
|
||||
|
||||
-type c2s_state() :: #state{}.
|
||||
@@ -35,7 +35,11 @@
|
||||
module :: atom(),
|
||||
function :: atom(),
|
||||
args = [] :: [aterm()] | '_' | '$1' | '$2',
|
||||
result = {res, rescode} :: rterm() | '_' | '$2'}).
|
||||
result = {res, rescode} :: rterm() | '_' | '$2',
|
||||
args_desc = none :: none | [string()],
|
||||
result_desc = none :: none | string(),
|
||||
args_example = none :: [any()],
|
||||
result_example = none :: any()}).
|
||||
|
||||
-type ejabberd_commands() :: #ejabberd_commands{name :: atom(),
|
||||
tags :: [atom()],
|
||||
@@ -44,7 +48,11 @@
|
||||
module :: atom(),
|
||||
function :: atom(),
|
||||
args :: [aterm()],
|
||||
result :: rterm()}.
|
||||
result :: rterm(),
|
||||
args_desc :: none | [string()],
|
||||
result_desc :: none | string(),
|
||||
args_example :: [any()],
|
||||
result_example :: any()}.
|
||||
|
||||
%% @type ejabberd_commands() = #ejabberd_commands{
|
||||
%% name = atom(),
|
||||
@@ -72,4 +80,3 @@
|
||||
|
||||
%% @type rterm() = {Name::atom(), Type::rtype()}.
|
||||
%% A result term is a tuple with the term name and the term type.
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
%%% published by the Free Software Foundation; either version 2 of the
|
||||
%%% License, or (at your option) any later version.
|
||||
%%%
|
||||
%%% This program is distributed in the hope that it will be useful,
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
%%% General Public License for more details.
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with this program; if not, write to the Free Software
|
||||
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
%%% 02111-1307 USA
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-record(request,
|
||||
{method :: method(),
|
||||
path = [] :: [binary()],
|
||||
q = [] :: [{binary() | nokey, binary()}],
|
||||
us = {<<>>, <<>>} :: {binary(), binary()},
|
||||
auth :: {binary(), binary()} |
|
||||
{auth_jid, {binary(), binary()}, jlib:jid()},
|
||||
lang = <<"">> :: binary(),
|
||||
data = <<"">> :: binary(),
|
||||
ip :: {inet:ip_address(), inet:port_number()},
|
||||
host = <<"">> :: binary(),
|
||||
port = 5280 :: inet:port_number(),
|
||||
tp = http :: protocol(),
|
||||
headers = [] :: [{atom() | binary(), binary()}]}).
|
||||
|
||||
-record(ws,
|
||||
{socket :: inet:socket() | tls:tls_socket(),
|
||||
sockmod = gen_tcp :: gen_tcp | tls,
|
||||
ws_autoexit = false :: boolean(),
|
||||
ip :: {inet:ip_address(), inet:port_number()},
|
||||
vsn :: vsn(),
|
||||
origin = <<"">> :: binary(),
|
||||
host = <<"">> :: binary(),
|
||||
port = 5280 :: inet:port_number(),
|
||||
path = [] :: [binary()],
|
||||
headers = [] :: [{atom() | binary(), binary()}],
|
||||
local_path = [] :: [binary()],
|
||||
q = [] :: [{binary() | nokey, binary()}],
|
||||
buf :: binary()}).
|
||||
|
||||
-type method() :: 'GET' | 'HEAD' | 'DELETE' | 'OPTIONS' | 'PUT' | 'POST' | 'TRACE'.
|
||||
-type protocol() :: http | https.
|
||||
-type http_request() :: #request{}.
|
||||
-type vsn() :: {'draft-hybi' | 'draft-hixie', non_neg_integer()}.
|
||||
@@ -86,11 +86,9 @@
|
||||
{<<"cols">>, Cols}],
|
||||
Value)).
|
||||
|
||||
%% Build an xmlelement for result
|
||||
-define(XRES(Text),
|
||||
?XAC(<<"p">>, [{<<"class">>, <<"result">>}], Text)).
|
||||
|
||||
%% Guide Link
|
||||
-define(XREST(Text), ?XRES((?T(Text)))).
|
||||
|
||||
-define(GL(Ref, Title),
|
||||
@@ -100,6 +98,5 @@
|
||||
{<<"target">>, <<"_blank">>}],
|
||||
[?C(<<"[Guide: ", Title/binary, "]">>)])])).
|
||||
|
||||
%% h1 with a Guide Link
|
||||
-define(H1GL(Name, Ref, Title),
|
||||
[?XC(<<"h1">>, Name), ?GL(Ref, Title)]).
|
||||
@@ -46,6 +46,7 @@
|
||||
|
||||
-type tlsopts() :: [{encrypt, tls | starttls | none} |
|
||||
{tls_cacertfile, binary() | undefined} |
|
||||
{tls_certfile, binary() | undefined} |
|
||||
{tls_depth, non_neg_integer() | undefined} |
|
||||
{tls_verify, hard | soft | false}].
|
||||
|
||||
@@ -166,6 +166,9 @@
|
||||
-define(NS_STREAM,
|
||||
<<"http://etherx.jabber.org/streams">>).
|
||||
|
||||
-define(NS_FLASH_STREAM,
|
||||
<<"http://www.jabber.com/streams/flash">>).
|
||||
|
||||
-define(NS_STANZAS,
|
||||
<<"urn:ietf:params:xml:ns:xmpp-stanzas">>).
|
||||
|
||||
@@ -212,6 +215,8 @@
|
||||
|
||||
-define(NS_BOB, <<"urn:xmpp:bob">>).
|
||||
|
||||
-include("xml.hrl").
|
||||
|
||||
-define(STANZA_ERROR(Code, Type, Condition),
|
||||
#xmlel{name = <<"error">>,
|
||||
attrs = [{<<"code">>, Code}, {<<"type">>, Type}],
|
||||
@@ -269,6 +274,10 @@
|
||||
?STANZA_ERROR(<<"402">>, <<"auth">>,
|
||||
<<"payment-required">>)).
|
||||
|
||||
-define(ERR_POLICY_VIOLATION,
|
||||
?STANZA_ERROR(<<"405">>, <<"cancel">>,
|
||||
<<"policy-violation">>)).
|
||||
|
||||
-define(ERR_RECIPIENT_UNAVAILABLE,
|
||||
?STANZA_ERROR(<<"404">>, <<"wait">>,
|
||||
<<"recipient-unavailable">>)).
|
||||
@@ -610,19 +619,6 @@
|
||||
|
||||
-type(ljid() :: {binary(), binary(), binary()}).
|
||||
|
||||
-record(xmlel,
|
||||
{
|
||||
name = <<"">> :: binary(),
|
||||
attrs = [] :: [attr()],
|
||||
children = [] :: [xmlel() | cdata()]
|
||||
}).
|
||||
|
||||
-type(cdata() :: {xmlcdata, CData::binary()}).
|
||||
|
||||
-type(attr() :: {Name::binary(), Value::binary()}).
|
||||
|
||||
-type(xmlel() :: #xmlel{}).
|
||||
|
||||
-record(iq, {id = <<"">> :: binary(),
|
||||
type = get :: get | set | result | error,
|
||||
xmlns = <<"">> :: binary(),
|
||||
@@ -0,0 +1 @@
|
||||
-define(IS_VALID, true).
|
||||
@@ -18,19 +18,19 @@
|
||||
%%% 02111-1307 USA
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
-define(PRINT(Format, Args), io:format(Format, Args)).
|
||||
|
||||
-record(request,
|
||||
{method, % :: method(),
|
||||
path = [] :: [binary()],
|
||||
q = [] :: [{binary() | nokey, binary()}],
|
||||
us = {<<>>, <<>>} :: {binary(), binary()},
|
||||
auth :: {binary(), binary()} |
|
||||
{auth_jid, {binary(), binary()}, jlib:jid()},
|
||||
lang = <<"">> :: binary(),
|
||||
data = <<"">> :: binary(),
|
||||
ip :: {inet:ip_address(), inet:port_number()},
|
||||
host = <<"">> :: binary(),
|
||||
port = 5280 :: inet:port_number(),
|
||||
tp = http, % :: protocol(),
|
||||
headers = [] :: [{atom() | binary(), binary()}]}).
|
||||
-define(DEBUG(Format, Args),
|
||||
ejabberd_logger:debug_msg(?MODULE, ?LINE, Format, Args)).
|
||||
|
||||
-define(INFO_MSG(Format, Args),
|
||||
ejabberd_logger:info_msg(?MODULE, ?LINE, Format, Args)).
|
||||
|
||||
-define(WARNING_MSG(Format, Args),
|
||||
ejabberd_logger:warning_msg(?MODULE, ?LINE, Format, Args)).
|
||||
|
||||
-define(ERROR_MSG(Format, Args),
|
||||
ejabberd_logger:error_msg(?MODULE, ?LINE, Format, Args)).
|
||||
|
||||
-define(CRITICAL_MSG(Format, Args),
|
||||
ejabberd_logger:critical_msg(?MODULE, ?LINE, Format, Args)).
|
||||
@@ -98,6 +98,7 @@
|
||||
nicks = (?DICT):new() :: dict(),
|
||||
affiliations = (?DICT):new() :: dict(),
|
||||
history :: lqueue(),
|
||||
persist_history = false :: boolean(),
|
||||
subject = <<"">> :: binary(),
|
||||
subject_author = <<"">> :: binary(),
|
||||
just_created = false :: boolean(),
|
||||
@@ -19,6 +19,8 @@
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-define(mod_privacy_hrl, true).
|
||||
|
||||
-record(privacy, {us = {<<"">>, <<"">>} :: {binary(), binary()},
|
||||
default = none :: none | binary(),
|
||||
lists = [] :: [{binary(), [listitem()]}]}).
|
||||
@@ -21,17 +21,14 @@
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
%% Version
|
||||
-define(VERSION_5, 5).
|
||||
|
||||
%% Authentication methods
|
||||
-define(AUTH_ANONYMOUS, 0).
|
||||
|
||||
-define(AUTH_GSSAPI, 1).
|
||||
|
||||
-define(AUTH_PLAIN, 2).
|
||||
|
||||
%% Address Type
|
||||
-define(AUTH_NO_METHODS, 255).
|
||||
|
||||
-define(ATYP_IPV4, 1).
|
||||
@@ -40,14 +37,12 @@
|
||||
|
||||
-define(ATYP_IPV6, 4).
|
||||
|
||||
%% Commands
|
||||
-define(CMD_CONNECT, 1).
|
||||
|
||||
-define(CMD_BIND, 2).
|
||||
|
||||
-define(CMD_UDP, 3).
|
||||
|
||||
%% RFC 1928 replies
|
||||
-define(SUCCESS, 0).
|
||||
|
||||
-define(ERR_GENERAL_FAILURE, 1).
|
||||
@@ -66,7 +61,6 @@
|
||||
|
||||
-define(ERR_ADDRESS_TYPE_NOT_SUPPORTED, 8).
|
||||
|
||||
%% RFC 1928 defined timeout.
|
||||
-define(SOCKS5_REPLY_TIMEOUT, 10000).
|
||||
|
||||
-record(s5_request, {rsv = 0 :: integer(),
|
||||
@@ -4,13 +4,11 @@
|
||||
%%% compliance with the License. You should have received a copy of the
|
||||
%%% Erlang Public License along with this software. If not, it can be
|
||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||
%%%
|
||||
%%%
|
||||
%%% Software distributed under the License is distributed on an "AS IS"
|
||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
%%% the License for the specific language governing rights and limitations
|
||||
%%% under the License.
|
||||
%%%
|
||||
%%%
|
||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
||||
%%% Portions created by ProcessOne are Copyright 2006-2013, ProcessOne
|
||||
@@ -23,22 +21,16 @@
|
||||
%%% This file contains pubsub types definition.
|
||||
%%% ====================================================================
|
||||
|
||||
%% -------------------------------
|
||||
%% Pubsub constants
|
||||
-define(ERR_EXTENDED(E, C),
|
||||
mod_pubsub:extended_error(E, C)).
|
||||
|
||||
%% The actual limit can be configured with mod_pubsub's option max_items_node
|
||||
-define(MAXITEMS, 10).
|
||||
|
||||
%% this is currently a hard limit.
|
||||
%% Would be nice to have it configurable.
|
||||
-define(MAX_PAYLOAD_SIZE, 60000).
|
||||
|
||||
%% -------------------------------
|
||||
%% Pubsub types
|
||||
|
||||
%% @type hostPubsub() = string().
|
||||
-type(hostPubsub() :: binary()).
|
||||
%% <p><tt>hostPubsub</tt> is the name of the PubSub service. For example, it can be
|
||||
%% <tt>"pubsub.localhost"</tt>.</p>
|
||||
@@ -57,7 +49,6 @@
|
||||
-type(nodeId() :: binary()).
|
||||
%% @type nodeId() = binary().
|
||||
%% <p>A node is defined by a list of its ancestors. The last element is the name
|
||||
%% of the current node. For example:
|
||||
%% of the current node. For example:
|
||||
%% ```<<"/home/localhost/user">>'''</p>
|
||||
|
||||
@@ -74,7 +65,6 @@
|
||||
%% @type payload() = [#xmlelement{} | #xmlcdata{}].
|
||||
|
||||
%% @type stanzaError() = #xmlelement{}.
|
||||
%% Example:
|
||||
%% Example:
|
||||
%% ```{xmlelement, "error",
|
||||
%% [{"code", Code}, {"type", Type}],
|
||||
@@ -149,11 +139,6 @@
|
||||
).
|
||||
%% @type accessModel() = 'open' | 'presence' | 'roster' | 'authorize' | 'whitelist'.
|
||||
|
||||
%% @type pubsubIndex() = {pubsub_index, Index, Last, Free}
|
||||
%% Index = atom()
|
||||
%% Last = integer()
|
||||
%% Free = [integer()].
|
||||
%% internal pubsub index table
|
||||
-type(publishModel() :: 'publishers'
|
||||
| 'subscribers'
|
||||
| 'open'
|
||||
@@ -167,17 +152,6 @@
|
||||
free :: [mod_pubsub:nodeIdx()]
|
||||
}).
|
||||
|
||||
%% @type pubsubNode() = {pubsub_node, NodeId, Id, Parents, Type, Owners, Options}
|
||||
%% NodeId = {host() | ljid(), nodeId()}
|
||||
%% Id = nodeIdx()
|
||||
%% Parents = [nodeId()]
|
||||
%% Type = nodeType()
|
||||
%% Owners = [ljid()]
|
||||
%% Options = [nodeOption()].
|
||||
%% <p>This is the format of the <tt>nodes</tt> table. The type of the table
|
||||
%% is: <tt>set</tt>,<tt>ram/disc</tt>.</p>
|
||||
%% <p>The <tt>Parents</tt> and <tt>type</tt> fields are indexed.</p>
|
||||
%% <tt>id</tt> can be anything you want.
|
||||
-record(pubsub_node,
|
||||
{
|
||||
nodeid ,%:: {Host::mod_pubsub:host(), NodeId::mod_pubsub:nodeId()},
|
||||
@@ -188,49 +162,32 @@
|
||||
options = [] %:: mod_pubsub:nodeOptions()
|
||||
}).
|
||||
|
||||
%% @type pubsubState() = {pubsub_state, StateId, Items, Affiliation, Subscriptions}
|
||||
%% StateId = {ljid(), nodeIdx()}
|
||||
%% Items = [itemId()]
|
||||
%% Affiliation = affiliation()
|
||||
%% Subscriptions = [{subscription(), subId()}].
|
||||
%% <p>This is the format of the <tt>affiliations</tt> table. The type of the
|
||||
%% table is: <tt>set</tt>,<tt>ram/disc</tt>.</p>
|
||||
|
||||
%-record(pubsub_state,
|
||||
% {stateid, items = [], affiliation = none,
|
||||
% {stateid, nodeidx, items = [], affiliation = none,
|
||||
% subscriptions = []}).
|
||||
-record(pubsub_state,
|
||||
{
|
||||
stateid ,%:: {Entity::ljid(), NodeIdx::mod_pubsub:nodeIdx()},
|
||||
nodeidx ,%:: mod_pubsub:nodeIdx(),
|
||||
items = [] ,%:: [ItemId::mod_pubsub:itemId()],
|
||||
affiliation = 'none' ,%:: mod_pubsub:affiliation(),
|
||||
subscriptions = [] %:: [{mod_pubsub:subscription(), mod_pubsub:subId()}]
|
||||
}).
|
||||
|
||||
%% @type pubsubItem() = {pubsub_item, ItemId, Creation, Modification, Payload}
|
||||
%% ItemId = {itemId(), nodeIdx()}
|
||||
%% Creation = {now(), ljid()}
|
||||
%% Modification = {now(), ljid()}
|
||||
%% Payload = payload().
|
||||
%% <p>This is the format of the <tt>published items</tt> table. The type of the
|
||||
%% table is: <tt>set</tt>,<tt>disc</tt>,<tt>fragmented</tt>.</p>
|
||||
%-record(pubsub_item,
|
||||
% {itemid, creation = {unknown, unknown},
|
||||
% {itemid, nodeidx, creation = {unknown, unknown},
|
||||
% modification = {unknown, unknown}, payload = []}).
|
||||
|
||||
-record(pubsub_item,
|
||||
{
|
||||
itemid ,%:: {mod_pubsub:itemId(), mod_pubsub:nodeIdx()},
|
||||
nodeidx ,%:: mod_pubsub_nodeIdx(),
|
||||
creation = {unknown, unknown} ,%:: {erlang:timestamp(), ljid()},
|
||||
modification = {unknown, unknown} ,%:: {erlang:timestamp(), ljid()},
|
||||
payload = [] %:: mod_pubsub:payload()
|
||||
}).
|
||||
|
||||
%% @type pubsubSubscription() = {pubsub_subscription, SubId, Options}
|
||||
%% SubId = subId()
|
||||
%% Options = [nodeOption()].
|
||||
%% <p>This is the format of the <tt>subscriptions</tt> table. The type of the
|
||||
%% table is: <tt>set</tt>,<tt>ram/disc</tt>.</p>
|
||||
%-record(pubsub_subscription, {subid, options}).
|
||||
-record(pubsub_subscription,
|
||||
{
|
||||
@@ -238,13 +195,6 @@
|
||||
options %:: [] | mod_pubsub:subOptions()
|
||||
}).
|
||||
|
||||
%% @type pubsubLastItem() = {pubsub_last_item, NodeId, ItemId, Creation, Payload}
|
||||
%% NodeId = nodeIdx()
|
||||
%% ItemId = itemId()
|
||||
%% Creation = {now(),ljid()}
|
||||
%% Payload = payload().
|
||||
%% <p>This is the format of the <tt>last items</tt> table. it stores last item payload
|
||||
%% for every node</p>
|
||||
%-record(pubsub_last_item,
|
||||
% {nodeid, itemid, creation, payload}).
|
||||
|
||||
@@ -0,0 +1,685 @@
|
||||
%%% ====================================================================
|
||||
%%% ``The contents of this file are subject to the Erlang Public License,
|
||||
%%% Version 1.1, (the "License"); you may not use this file except in
|
||||
%%% compliance with the License. You should have received a copy of the
|
||||
%%% Erlang Public License along with this software. If not, it can be
|
||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||
%%%
|
||||
%%% Software distributed under the License is distributed on an "AS IS"
|
||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
%%% the License for the specific language governing rights and limitations
|
||||
%%% under the License.
|
||||
%%%
|
||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
||||
%%% Portions created by ProcessOne are Copyright 2006-2013, ProcessOne
|
||||
%%% All Rights Reserved.''
|
||||
%%% This software is copyright 2006-2013, ProcessOne.
|
||||
%%%
|
||||
%%% @copyright 2006-2013 ProcessOne
|
||||
%%% @author Karim Gemayel <karim.gemayel@process-one.net>
|
||||
%%% [http://www.process-one.net/]
|
||||
%%% @version {@vsn}, {@date} {@time}
|
||||
%%% @end
|
||||
%%% ====================================================================
|
||||
|
||||
%%% @headerfile "pubsub_dev.hrl"
|
||||
|
||||
-module(exmpp_pubsub).
|
||||
-author('karim.gemayel@process-one.net').
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
-include("pubsub_dev.hrl").
|
||||
|
||||
|
||||
%% --------------------------------------------------------------------
|
||||
%% Documentation / type definitions.
|
||||
%% --------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
%-- Affiliations --%
|
||||
-export_type([
|
||||
affiliation/0,
|
||||
%%
|
||||
affiliation_owner/0,
|
||||
affiliation_publisher/0,
|
||||
affiliation_publish_only/0,
|
||||
affiliation_member/0,
|
||||
affiliation_none/0,
|
||||
affiliation_outcast/0
|
||||
]).
|
||||
|
||||
%% @type affiliation_owner() = 'owner'.
|
||||
-type(affiliation_owner() :: 'owner').
|
||||
|
||||
%% @type affiliation_publisher() = 'publisher'.
|
||||
-type(affiliation_publisher() :: 'publisher').
|
||||
|
||||
%% @type affiliation_publish_only() = 'publish-only'.
|
||||
-type(affiliation_publish_only() :: 'publish-only').
|
||||
|
||||
%% @type affiliation_member() = 'member'.
|
||||
-type(affiliation_member() :: 'member').
|
||||
|
||||
%% @type affiliation_none() = 'none'.
|
||||
-type(affiliation_none() :: 'none').
|
||||
|
||||
%% @type affiliation_outcast() = 'outcast'.
|
||||
-type(affiliation_outcast() :: 'outcast').
|
||||
|
||||
%% @type affiliation() = Owner | Publisher | Publish_Only | Member | None | Outcast
|
||||
%% Owner = exmpp_pubsub:affiliation_owner()
|
||||
%% Publisher = exmpp_pubsub:affiliation_publisher()
|
||||
%% Publish_Only = exmpp_pubsub:affiliation_publish_only()
|
||||
%% Member = exmpp_pubsub:affiliation_member()
|
||||
%% None = exmpp_pubsub:affiliation_none()
|
||||
%% Outcast = exmpp_pubsub:affiliation_outcast().
|
||||
-type(affiliation() :: exmpp_pubsub:affiliation_owner()
|
||||
| exmpp_pubsub:affiliation_publisher()
|
||||
| exmpp_pubsub:affiliation_publish_only()
|
||||
| exmpp_pubsub:affiliation_member()
|
||||
| exmpp_pubsub:affiliation_none()
|
||||
| exmpp_pubsub:affiliation_outcast()
|
||||
).
|
||||
|
||||
|
||||
%%
|
||||
|
||||
%-- Things identifiers --%
|
||||
-export_type([
|
||||
index/0,
|
||||
itemId/0,
|
||||
itemIds/0,
|
||||
level/0,
|
||||
nodeId/0,
|
||||
nodeIdx/0,
|
||||
subId/0,
|
||||
plugin/0
|
||||
]).
|
||||
|
||||
%% @type index() = 'node'.
|
||||
-type(index() :: 'node' ).
|
||||
|
||||
%% @type itemId() = binary().
|
||||
-type(itemId() :: binary()).
|
||||
|
||||
%% @type itemIds() = [ItemId::exmpp_pubsub:itemId(),...].
|
||||
-type(itemIds() :: [ItemId::exmpp_pubsub:itemId(),...]).
|
||||
|
||||
%% @type level() = non_neg_integer().
|
||||
-type(level() :: non_neg_integer()).
|
||||
|
||||
%% @type nodeId() = binary().
|
||||
-type(nodeId() :: binary()).
|
||||
|
||||
%% @type nodeIdx() = non_neg_integer().
|
||||
-type(nodeIdx() :: non_neg_integer()).
|
||||
|
||||
%% @type plugin() = module().
|
||||
-type(plugin() :: module()).
|
||||
|
||||
%% @type subId() = binary().
|
||||
-type(subId() :: binary()).
|
||||
|
||||
|
||||
-export_type([
|
||||
t_now/0
|
||||
]).
|
||||
|
||||
%% Temporary -type, until calendar.erl -type is exported
|
||||
-type(t_now()
|
||||
:: {MegaSec::non_neg_integer(),
|
||||
Sec::non_neg_integer(),
|
||||
MilliSec::non_neg_integer()}
|
||||
).
|
||||
|
||||
|
||||
%%
|
||||
-export_type([
|
||||
feature/0,
|
||||
features/0,
|
||||
pubsub_feature/0,
|
||||
pubsub_features/0
|
||||
]).
|
||||
|
||||
-type(feature() :: binary()).
|
||||
|
||||
-type(features() :: Features::[Feature::exmpp_pubsub:feature(),...]).
|
||||
|
||||
-type(pubsub_feature() :: exmpp_pubsub:feature()).
|
||||
|
||||
-type(pubsub_features() :: Pubsub_Features::[Pubsub_Feature::exmpp_pubsub:feature(),...]).
|
||||
|
||||
%%
|
||||
|
||||
%-- Payload types --%
|
||||
-export_type([
|
||||
payload/0,
|
||||
%%
|
||||
payload_empty/0,
|
||||
payload_full/0
|
||||
]).
|
||||
|
||||
%% @type payload_empty() = [].
|
||||
-type(payload_empty() :: []).
|
||||
|
||||
%% @type payload_full() = #xmlel{}.
|
||||
-type(payload_full() :: xmlel()).
|
||||
|
||||
%% @type payload() = Empty_Payload | Full_Payload
|
||||
%% Empty_Payload = exmpp_pubsub:payload_empty()
|
||||
%% Full_Payload = exmpp_pubsub:payload_full().
|
||||
-type(payload() :: exmpp_pubsub:payload_empty()
|
||||
| exmpp_pubsub:payload_full()
|
||||
).
|
||||
|
||||
|
||||
%%
|
||||
|
||||
%-- Pusbub Host --%
|
||||
-export_type([
|
||||
host/0,
|
||||
%%
|
||||
host_pubsub/0,
|
||||
host_pep/0
|
||||
]).
|
||||
|
||||
%% @type host_pubsub() = xmpp_jid:domain_jid().
|
||||
%% ```<<"pubsub.shakespeare.lit">>'''
|
||||
%% Identifier type of the Pubsub service
|
||||
-type(host_pubsub() :: binary()).
|
||||
|
||||
%% @type host_pep() = xmpp_jid:usr_contact_bare().
|
||||
%% ```{<<"juliet">>, <<"capulet.lit">>, undefined}'''
|
||||
%% Identifier type of the Pubsub-On-Jid service
|
||||
-type(host_pep() :: xmpp_jid:usr_contact_bare()).
|
||||
|
||||
%% @type host() = Pubsub_Host | Pubsub_On_Jid_Host
|
||||
%% Pubsub_Host = exmpp_pubsub:host_pubsub()
|
||||
%% Pubsub_On_Jid_Host = exmpp_pubsub:host_pep().
|
||||
%% Identifier types of the Pubsub and PEP (Pubsub-On-Jid) services
|
||||
%% ```* Pubsub_Host : <<"pubsub.shakespeare.lit">>
|
||||
%% * Pubsub_PEP : {<<"juliet">>, <<"capulet.lit">>, undefined}'''
|
||||
-type(host() :: exmpp_pubsub:host_pubsub()
|
||||
| exmpp_pubsub:host_pep()
|
||||
).
|
||||
|
||||
|
||||
%%
|
||||
|
||||
%-- Subscription States --%
|
||||
-export_type([
|
||||
subscription_state/0,
|
||||
%%
|
||||
subscription_state_none/0,
|
||||
subscription_state_pending/0,
|
||||
subscription_state_unconfigured/0,
|
||||
subscription_state_subscribed/0
|
||||
]).
|
||||
|
||||
%% @type subscription_state_none() = 'none'.
|
||||
-type(subscription_state_none() :: 'none').
|
||||
|
||||
%% @type subscription_state_pending() = 'pending'.
|
||||
-type(subscription_state_pending() :: 'pending').
|
||||
|
||||
%% @type subscription_state_unconfigured() = 'unconfigured'.
|
||||
-type(subscription_state_unconfigured() :: 'unconfigured').
|
||||
|
||||
%% @type subscription_state_subscribed() = 'subscribed'.
|
||||
-type(subscription_state_subscribed() :: 'subscribed').
|
||||
|
||||
%% @type subscription_state() = None | Pending | Unconfigured | Subscribed
|
||||
%% None = exmpp_pubsub:subscription_state_none()
|
||||
%% Pending = exmpp_pubsub:subscription_state_pending()
|
||||
%% Unconfigured = exmpp_pubsub:subscription_state_unconfigured()
|
||||
%% Subscribed = exmpp_pubsub:subscription_state_subscribed()
|
||||
-type(subscription_state() :: exmpp_pubsub:subscription_state_pending()
|
||||
| exmpp_pubsub:subscription_state_unconfigured()
|
||||
| exmpp_pubsub:subscription_state_subscribed()
|
||||
).
|
||||
|
||||
%%
|
||||
|
||||
%-- Subscription -- %%
|
||||
-export_type([
|
||||
subscriptions/0,
|
||||
subscription/0,
|
||||
%%
|
||||
subscription_subscribed/0,
|
||||
subscription_unconfigured/0,
|
||||
subscription_pending/0
|
||||
]).
|
||||
|
||||
-type(subscription_subscribed()
|
||||
:: {Subscription_State :: exmpp_pubsub:subscription_state_subscribed(),
|
||||
SubId :: exmpp_pubsub:subId(),
|
||||
Resource :: undefined | xmpp_jid:resource_jid() | {'caps', xmpp_jid:resource_jid()},
|
||||
Subscription_Options :: [] | pubsub_options:options_subscription()}
|
||||
).
|
||||
|
||||
-type(subscription_unconfigured()
|
||||
:: {Subscription_State :: exmpp_pubsub:subscription_state_unconfigured(),
|
||||
SubId :: exmpp_pubsub:subId(),
|
||||
Resource :: undefined | xmpp_jid:resource_jid() | {'caps', xmpp_jid:resource_jid()},
|
||||
Subscription_Options :: []}
|
||||
).
|
||||
|
||||
-type(subscription_pending()
|
||||
:: {Subscription_State :: exmpp_pubsub:subscription_state_pending(),
|
||||
SubId :: exmpp_pubsub:subId(),
|
||||
Resource :: undefined | xmpp_jid:resource_jid() | {'caps', xmpp_jid:resource_jid()},
|
||||
Subscription_Options :: []}
|
||||
).
|
||||
|
||||
%% -type(subscription()
|
||||
%% :: {Subscription_State :: exmpp_pubsub:subscription_state(),
|
||||
%% SubId :: exmpp_pubsub:subId(),
|
||||
%% Resource :: undefined | xmpp_jid:resource_jid() | {'caps', xmpp_jid:resource_jid()},
|
||||
%% Subscription_Options :: [] | pubsub_options:options_subscription()}
|
||||
%% %% :: exmpp_pubsub:subscription_subscribed()
|
||||
%% %% | exmpp_pubsub:subscription_pending()
|
||||
%% %% | exmpp_pubsub:subscription_unconfigured()
|
||||
%% ).
|
||||
|
||||
-type(subscriptions()
|
||||
:: [exmpp_pubsub:subscription(),...]
|
||||
%% :: [exmpp_pubsub:subscription_subscribed(),...]
|
||||
%% | [exmpp_pubsub:subscription_unconfigured(),...]
|
||||
%% | [exmpp_pubsub:subscription_pending(),...]
|
||||
).
|
||||
|
||||
%% TODO : commented -type unions return the following dialyzer error (bug ?) :
|
||||
%% ...
|
||||
%% Adding information from /home/meta/otp-exmpp.plt to ejabberd.plt...
|
||||
%%=ERROR REPORT==== 29-Jul-2011::15:14:42 ===
|
||||
%Error in process <0.2604.0> with exit value: {function_clause,[{erl_types,inf_tuples_in_sets,4},{erl_types,inf_tuple_sets,4},{erl_types,inf_tuple_sets,3},{erl_types,t_inf,3},{erl_types,t_inf_lists_strict,4},{erl_types,t_inf,3},{dialyzer_typesig,solve_one_c...
|
||||
%%
|
||||
%%
|
||||
%%dialyzer: Analysis failed with error: {function_clause,[{erl_types,inf_tuples_in_sets,4},
|
||||
%% {erl_types,inf_tuple_sets,4},
|
||||
%% {erl_types,inf_tuple_sets,3},
|
||||
%% {erl_types,t_inf,3},
|
||||
%% {erl_types,t_inf_lists_strict,4},
|
||||
%% {erl_types,t_inf,3},
|
||||
%% {dialyzer_typesig,solve_one_c,...},
|
||||
%% {dialyzer_typesig,...}]}
|
||||
%%Last messages in the log cache:
|
||||
%% Typesig analysis for SCC: [{ejabberd_web_admin,make_xhtml,5}]
|
||||
%% Typesig analysis for SCC: [{ejabberd_web_admin,make_xhtml,4}]
|
||||
%% Typesig analysis for SCC: [{ejabberd_web_admin,process_admin,2}]
|
||||
%% Typesig analysis for SCC: [{ejabberd_web_admin,process,2}]
|
||||
%% Typesig analysis for SCC: [{mod_stats,get_local_stat,3}]
|
||||
%% Typesig analysis for SCC: [{mod_stats,get_local_stats,3}]
|
||||
%% Typesig analysis for SCC: [{mod_stats,process_local_iq,3}]
|
||||
%% Typesig analysis for SCC: [{mod_register_web,send_registration_notifications,2}]
|
||||
%% Typesig analysis for SCC: [{mod_register_web,process,2}]
|
||||
%% Typesig analysis for SCC: [{pubsub_db,create_node,5}]
|
||||
|
||||
%%
|
||||
|
||||
|
||||
%% Pubsub #xmlel{} templates
|
||||
|
||||
|
||||
%% --------------------------------------------------------------------
|
||||
%% Functions.
|
||||
%% --------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
%% @spec nodeId() -> NodeId::exmpp_pubsub:nodeId()
|
||||
-spec(nodeId/0 :: () -> NodeId::exmpp_pubsub:nodeId()).
|
||||
|
||||
nodeId() ->
|
||||
randoms:get_string().
|
||||
|
||||
%% @spec subId() -> SubId::exmpp_pubsub:subId()
|
||||
-spec(subId/0 :: () -> SubId::exmpp_pubsub:subId()).
|
||||
|
||||
subId() ->
|
||||
{T1, T2, T3} = now(),
|
||||
list_to_binary(lists:flatten(io_lib:fwrite("~.16B~.16B~.16B", [T1, T2, T3]))).
|
||||
|
||||
%% @spec itemId() -> ItemId::exmpp_pubsub:itemId()
|
||||
-spec(itemId/0 :: () -> ItemId::exmpp_pubsub:itemId()).
|
||||
|
||||
itemId() ->
|
||||
{T1, T2, T3} = now(),
|
||||
list_to_binary(lists:flatten(io_lib:fwrite("~.16B~.16B~.16B", [T1, T2, T3]))).
|
||||
|
||||
id() ->
|
||||
{T1, T2, T3} = now(),
|
||||
list_to_binary(lists:flatten(io_lib:fwrite("~.16B~.16B~.16B", [T1, T2, T3]))).
|
||||
|
||||
|
||||
|
||||
%%
|
||||
-spec(subscription_subscribed/2 ::
|
||||
(
|
||||
Resource :: undefined
|
||||
| xmpp_jid:resource_jid()
|
||||
| {'caps', xmpp_jid:resource_jid()},
|
||||
Subscription_Options :: [] | pubsub_options:options_subscription())
|
||||
-> Subscription_Subscribed::exmpp_pubsub:subscription_subscribed()
|
||||
).
|
||||
|
||||
subscription_subscribed(Resource, Subscription_Options) ->
|
||||
{'subscribed', subId(), Resource, Subscription_Options}.
|
||||
|
||||
%%
|
||||
-spec(subscription_pending/2 ::
|
||||
(
|
||||
Resource :: undefined
|
||||
| xmpp_jid:resource_jid()
|
||||
| {'caps', xmpp_jid:resource_jid()},
|
||||
Subscription_Options :: [] | pubsub_options:options_subscription())
|
||||
-> Subscription_Pending::exmpp_pubsub:subscription_pending()
|
||||
).
|
||||
|
||||
subscription_pending(Resource, Subscription_Options) ->
|
||||
{'pending', subId(), Resource, Subscription_Options}.
|
||||
|
||||
|
||||
|
||||
%% Pubsub Xmlel templates
|
||||
|
||||
xmlcdata(CData) ->
|
||||
{xmlcdata, CData}.
|
||||
|
||||
xmlattr(Name, Value) ->
|
||||
{Name, Value}.
|
||||
|
||||
|
||||
xmlel('disco#info', Name, Attrs, Children) ->
|
||||
xmlel(?NS_DISCO_INFO, Name, Attrs, Children);
|
||||
xmlel('disco#items', Name, Attrs, Children) ->
|
||||
xmlel(?NS_DISCO_ITEMS, Name, Attrs, Children);
|
||||
xmlel('jabber:client', Name, Attrs, Children) ->
|
||||
xmlel(?NS_JABBER_CLIENT, Name, Attrs, Children);
|
||||
xmlel('pubsub', Name, Attrs, Children) ->
|
||||
xmlel(?NS_PUBSUB, Name, Attrs, Children);
|
||||
xmlel('pubsub#event', Name, Attrs, Children) ->
|
||||
xmlel(?NS_PUBSUB_EVENT, Name, Attrs, Children);
|
||||
xmlel('pubsub#owner', Name, Attrs, Children) ->
|
||||
xmlel(?NS_PUBSUB_OWNER, Name, Attrs, Children);
|
||||
xmlel('shim', Name, Attrs, Children) ->
|
||||
xmlel(?NS_SHIM, Name, Attrs, Children);
|
||||
xmlel(NS, Name, Attrs, Children) ->
|
||||
#xmlel{name = Name, attrs = [{<<"xmlns">>, NS} | Attrs], children = Children}.
|
||||
%%
|
||||
xmlattr_affiliation(Affiliation) ->
|
||||
xmlattr(<<"affiliation">>, list_to_binary(atom_to_list(Affiliation))).
|
||||
%%
|
||||
xmlattr_category(Category) ->
|
||||
xmlattr(<<"category">>, Category).
|
||||
%%
|
||||
xmlattr_id(ItemId) ->
|
||||
xmlattr(<<"id">>, ItemId).
|
||||
%%
|
||||
xmlattr_jid(Jid) ->
|
||||
xmlattr(<<"jid">>, Jid).
|
||||
%%
|
||||
xmlattr_name(Name) ->
|
||||
xmlattr(<<"name">>, Name).
|
||||
%%
|
||||
xmlattr_node(NodeId) ->
|
||||
xmlattr(<<"node">>, NodeId).
|
||||
%%
|
||||
xmlattr_publisher(Publisher) ->
|
||||
xmlattr(<<"publisher">>, Publisher).
|
||||
%%
|
||||
xmlattr_subid(SubId) ->
|
||||
xmlattr(<<"subid">>, SubId).
|
||||
%%
|
||||
xmlattr_subscription(Subscription_State) ->
|
||||
xmlattr(<<"subscription">>, list_to_binary(atom_to_list(Subscription_State))).
|
||||
%%
|
||||
xmlattr_type(Type) when is_atom(Type)->
|
||||
xmlattr(<<"type">>, list_to_binary(atom_to_list(Type)));
|
||||
%%
|
||||
xmlattr_type(Type) ->
|
||||
xmlattr(<<"type">>, Type).
|
||||
%%
|
||||
xmlattr_uri(URI) ->
|
||||
xmlattr(<<"uri">>, URI).
|
||||
%%
|
||||
xmlattr_var(Var) ->
|
||||
xmlattr(<<"var">>, Var).
|
||||
|
||||
%%
|
||||
xmlel_affiliation('pubsub', NodeId, Affiliation) ->
|
||||
xmlel('pubsub', <<"affiliation">>,
|
||||
[xmlattr_node(NodeId),
|
||||
xmlattr_affiliation(Affiliation)],
|
||||
[]);
|
||||
xmlel_affiliation('pubsub#owner', Jid, Affiliation) ->
|
||||
xmlel('pubsub#owner', <<"affiliation">>,
|
||||
[xmlattr_jid(Jid),
|
||||
xmlattr_affiliation(Affiliation)],
|
||||
[]).
|
||||
%%
|
||||
xmlel_affiliations('pubsub', Xmlels) ->
|
||||
xmlel('pubsub', <<"affiliations">>, [], Xmlels).
|
||||
|
||||
xmlel_affiliations('pubsub#owner', NodeId, Xmlels) ->
|
||||
xmlel('pubsub#owner', <<"affiliations">>, [xmlattr_node(NodeId)], Xmlels).
|
||||
%%
|
||||
xmlel_create(NodeId) ->
|
||||
xmlel('pubsub', <<"create">>, [xmlattr_node(NodeId)], []).
|
||||
|
||||
%%
|
||||
xmlel_configure('pubsub#owner', NodeId, Xmlels) ->
|
||||
xmlel('pubsub#owner', <<"configure">>, [xmlattr_node(NodeId)], Xmlels).
|
||||
|
||||
%%
|
||||
xmlel_default('pubsub', Xmlels) ->
|
||||
xmlel('pubsub', <<"default">>, [], Xmlels);
|
||||
%%
|
||||
xmlel_default('pubsub#owner', Xmlels) ->
|
||||
xmlel('pubsub#owner', <<"default">>, [], Xmlels).
|
||||
|
||||
%%
|
||||
xmlel_default('pubsub', NodeId, Xmlels) ->
|
||||
xmlel('pubsub', <<"default">>, [xmlattr_node(NodeId)], Xmlels).
|
||||
|
||||
%%
|
||||
xmlel_delete(NodeId, RedirectURI) ->
|
||||
xmlel('pubsub#event', <<"delete">>,
|
||||
[xmlattr_node(NodeId)],
|
||||
case RedirectURI of
|
||||
undefined -> [];
|
||||
_RedirectURI -> [xmlel_redirect(RedirectURI)]
|
||||
end).
|
||||
%%
|
||||
xmlel_event(Xmlels) ->
|
||||
xmlel('pubsub#event', <<"event">>, [], Xmlels).
|
||||
%%
|
||||
xmlel_feature('disco#info', Feature) ->
|
||||
xmlel('disco#info', <<"feature">>, [xmlattr_var(Feature)], []).
|
||||
%%
|
||||
xmlel_header(SubId) ->
|
||||
xmlel('shim', <<"header">>, [xmlattr_name(<<"SubID">>)], [xmlcdata(SubId)]).
|
||||
%%
|
||||
xmlel_headers(Xmlels_Header) ->
|
||||
xmlel('shim', <<"headers">>, [], Xmlels_Header).
|
||||
|
||||
|
||||
xmlel_identity('disco#info', Category, Type, Name) ->
|
||||
xmlel('disco#info', <<"identity">>,
|
||||
case Name of
|
||||
undefined ->
|
||||
[xmlattr_category(Category),
|
||||
xmlattr_type(Type)];
|
||||
_ ->
|
||||
[xmlattr_category(Category),
|
||||
xmlattr_name(Name),
|
||||
xmlattr_type(Type)]
|
||||
end,
|
||||
[]).
|
||||
|
||||
%%
|
||||
xmlel_item('pubsub', ItemId) ->
|
||||
xmlel('pubsub', <<"item">>, [xmlattr_id(ItemId)], []).
|
||||
|
||||
%%
|
||||
xmlel_item('disco#items', ItemId, Jid) ->
|
||||
xmlel('disco#items', <<"item">>,
|
||||
[xmlattr_name(ItemId),
|
||||
xmlattr_jid(Jid)],
|
||||
[]);
|
||||
xmlel_item('pubsub', ItemId, Payload) ->
|
||||
xmlel('pubsub', <<"item">>, [xmlattr_id(ItemId)],
|
||||
case Payload of
|
||||
[] -> [];
|
||||
_Payload -> [Payload]
|
||||
end).
|
||||
|
||||
xmlel_item('disco#items', NodeId, Jid, Name) ->
|
||||
xmlel('disco#items', <<"item">>,
|
||||
case Name of
|
||||
undefined ->
|
||||
[xmlattr_jid(Jid),
|
||||
xmlattr_node(NodeId)];
|
||||
_ ->
|
||||
[xmlattr_jid(Jid),
|
||||
xmlattr_node(NodeId),
|
||||
xmlattr_name(Name)]
|
||||
end,
|
||||
[]);
|
||||
%%
|
||||
xmlel_item('pubsub#event', ItemId, Publisher, Payload) ->
|
||||
xmlel('pubsub#event', <<"item">>,
|
||||
case Publisher of
|
||||
undefined ->
|
||||
[xmlattr_id(ItemId)];
|
||||
_Publisher ->
|
||||
[xmlattr_id(ItemId),
|
||||
xmlattr_publisher(Publisher)]
|
||||
end,
|
||||
case Payload of
|
||||
[] -> [];
|
||||
_Payload -> [Payload]
|
||||
end).
|
||||
%%
|
||||
xmlel_items('pubsub', NodeId, Xmlels) ->
|
||||
xmlel('pubsub', <<"items">>, [xmlattr_node(NodeId)], Xmlels);
|
||||
%%
|
||||
xmlel_items('pubsub#event', undefined = _NodeId, Xmlels) ->
|
||||
xmlel('pubsub#event', <<"items">>, [], Xmlels);
|
||||
%%
|
||||
xmlel_items('pubsub#event', NodeId, Xmlels) ->
|
||||
xmlel('pubsub#event', <<"items">>, [xmlattr_node(NodeId)], Xmlels).
|
||||
%%
|
||||
xmlel_items('pubsub#event', NodeId, undefined = _ItemId, _Publisher, _Payload) ->
|
||||
xmlel('pubsub#event', <<"items">>, [xmlattr_node(NodeId)], []);
|
||||
xmlel_items('pubsub#event', NodeId, ItemId, Publisher, Payload) ->
|
||||
xmlel('pubsub#event', <<"items">>,
|
||||
[xmlattr_node(NodeId)],
|
||||
[xmlel_item('pubsub#event', ItemId, Publisher, Payload)]).
|
||||
%%
|
||||
xmlel_message(undefined = _Type, Xmlels) ->
|
||||
xmlel_message('normal', Xmlels);
|
||||
xmlel_message(Type, Xmlels) ->
|
||||
xmlel('jabber:client', <<"message">>,
|
||||
[xmlattr_type(Type),
|
||||
xmlattr_id(_Id = id())],
|
||||
Xmlels).
|
||||
%%
|
||||
xmlel_options('pubsub', NodeId, Jid, SubId, Xmlels) ->
|
||||
xmlel('pubsub', <<"options">>,
|
||||
case SubId of
|
||||
undefined ->
|
||||
[xmlattr_node(NodeId),
|
||||
xmlattr_jid(Jid)];
|
||||
_ ->
|
||||
[xmlattr_node(NodeId),
|
||||
xmlattr_jid(Jid),
|
||||
xmlattr_subid(SubId)]
|
||||
end,
|
||||
Xmlels).
|
||||
%%
|
||||
xmlel_publish('pubsub', NodeId, Xmlels) ->
|
||||
xmlel('pubsub', <<"publish">>, [xmlattr_node(NodeId)], Xmlels).
|
||||
%%
|
||||
xmlel_purge(NodeId) ->
|
||||
xmlel('pubsub#event', <<"purge">>, [xmlattr_node(NodeId)], []).
|
||||
|
||||
%%
|
||||
xmlel_query('disco#info', Xmlels) ->
|
||||
xmlel('disco#info', <<"query">>, [], Xmlels);
|
||||
%%
|
||||
xmlel_query('disco#items', Xmlels) ->
|
||||
xmlel('disco#items', <<"query">>, [], Xmlels).
|
||||
|
||||
%%
|
||||
xmlel_query('disco#info', NodeId, Xmlels) ->
|
||||
xmlel('disco#info', <<"query">>, [xmlattr_node(NodeId)], Xmlels);
|
||||
xmlel_query('disco#items', NodeId, Xmlels) ->
|
||||
xmlel('disco#items', 'query', [xmlattr_node(NodeId)], Xmlels).
|
||||
|
||||
%%
|
||||
xmlel_redirect(RedirectURI) ->
|
||||
xmlel('pubsub#event', <<"redirect">>, [xmlattr_uri(RedirectURI)], []).
|
||||
%%
|
||||
xmlel_retract(undefined = _ItemId) ->
|
||||
xmlel('pubsub#event', <<"retract">>, [], []);
|
||||
xmlel_retract(ItemId) ->
|
||||
xmlel('pubsub#event', <<"retract">>, [xmlattr_id(ItemId)], []).
|
||||
%%
|
||||
xmlel_subscription('pubsub', NodeId, Jid, SubId, Subscription_State) ->
|
||||
xmlel('pubsub', <<"subscription">>,
|
||||
[xmlattr_node(NodeId),
|
||||
xmlattr_jid(Jid),
|
||||
xmlattr_subid(SubId),
|
||||
xmlattr_subscription(Subscription_State)],
|
||||
[]);
|
||||
xmlel_subscription('pubsub#event', NodeId, Jid, SubId, Subscription_State) ->
|
||||
xmlel('pubsub#event', <<"subscription">>,
|
||||
case SubId of
|
||||
undefined ->
|
||||
[xmlattr_node(NodeId),
|
||||
xmlattr_jid(Jid),
|
||||
xmlattr_subscription(Subscription_State)];
|
||||
_SubId ->
|
||||
[xmlattr_node(NodeId),
|
||||
xmlattr_jid(Jid),
|
||||
xmlattr_subid(SubId),
|
||||
xmlattr_subscription(Subscription_State)]
|
||||
end,
|
||||
[]).
|
||||
%%
|
||||
xmlel_subscription('pubsub#owner', Jid, SubId, Subscription_State) ->
|
||||
xmlel('pubsub#owner', <<"subscription">>,
|
||||
case SubId of
|
||||
undefined ->
|
||||
[xmlattr_jid(Jid),
|
||||
xmlattr_subscription(Subscription_State)];
|
||||
_SubId ->
|
||||
[xmlattr_jid(Jid),
|
||||
xmlattr_subid(SubId),
|
||||
xmlattr_subscription(Subscription_State)]
|
||||
end,
|
||||
[]).
|
||||
%%
|
||||
xmlel_subscriptions('pubsub', Xmlels) ->
|
||||
xmlel('pubsub', <<"subscriptions">>, [], Xmlels).
|
||||
|
||||
xmlel_subscriptions('pubsub#owner', NodeId, Xmlels) ->
|
||||
xmlel('pubsub#owner', <<"subscriptions">>, [xmlattr_node(NodeId)], Xmlels).
|
||||
%%
|
||||
xmlel_publish(NodeId, undefined = _ItemId) ->
|
||||
xmlel('pubsub', <<"publish">>, [xmlattr_node(NodeId)], []);
|
||||
xmlel_publish(NodeId, ItemId) ->
|
||||
xmlel('pubsub', <<"publish">>,
|
||||
[xmlattr_node(NodeId)],
|
||||
[xmlel_item('pubsub', ItemId)]).
|
||||
%%
|
||||
xmlel_pubsub('pubsub', Children) ->
|
||||
xmlel('pubsub', <<"pubsub">>, [], Children);
|
||||
%%
|
||||
xmlel_pubsub('pubsub#owner', Children) ->
|
||||
xmlel('pubsub#owner', <<"pubsub">>, [], Children).
|
||||
|
||||
@@ -0,0 +1,863 @@
|
||||
%%% ====================================================================
|
||||
%%% ``The contents of this file are subject to the Erlang Public License,
|
||||
%%% Version 1.1, (the "License"); you may not use this file except in
|
||||
%%% compliance with the License. You should have received a copy of the
|
||||
%%% Erlang Public License along with this software. If not, it can be
|
||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||
%%%
|
||||
%%% Software distributed under the License is distributed on an "AS IS"
|
||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
%%% the License for the specific language governing rights and limitations
|
||||
%%% under the License.
|
||||
%%%
|
||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
||||
%%% Portions created by ProcessOne are Copyright 2006-2013, ProcessOne
|
||||
%%% All Rights Reserved.''
|
||||
%%% This software is copyright 2006-2013, ProcessOne.
|
||||
%%%
|
||||
%%% @copyright 2006-2013 ProcessOne
|
||||
%%% @author Christophe Romain <christophe.romain@process-one.net>
|
||||
%%% [http://www.process-one.net/]
|
||||
%%% @author Karim Gemayel <karim.gemayel@process-one.net>
|
||||
%%% [http://www.process-one.net/]
|
||||
%%% @version {@vsn}, {@date} {@time}
|
||||
%%% @end
|
||||
%%% ====================================================================
|
||||
|
||||
%%% @headerfile "pubsub_dev.hrl"
|
||||
|
||||
-module(mod_pubsub_dev).
|
||||
-author('christophe.romain@process-one.net').
|
||||
-author('karim.gemayel@process-one.net').
|
||||
-version('1.13-0').
|
||||
|
||||
-behaviour(gen_server).
|
||||
-behaviour(gen_mod).
|
||||
|
||||
-include("pubsub_dev.hrl").
|
||||
-include("pubsub_api.hrl").
|
||||
|
||||
-compile(export_all).
|
||||
%%% Export Functions
|
||||
|
||||
%% API and gen_server callbacks
|
||||
-export([
|
||||
start_link/2,
|
||||
start/2,
|
||||
stop/1,
|
||||
init/1,
|
||||
handle_call/3,
|
||||
handle_cast/2,
|
||||
handle_info/2,
|
||||
terminate/2,
|
||||
code_change/3
|
||||
]).
|
||||
|
||||
%%
|
||||
-export_type([
|
||||
resource_show/0,
|
||||
presence_cache/0
|
||||
]).
|
||||
|
||||
-type(resource_show()
|
||||
:: {Resource :: xmpp_jid:resource_jid(),
|
||||
Show :: 'away' | 'chat' | 'dnd' | 'online' | 'xa' }
|
||||
).
|
||||
|
||||
-type(presence_cache() :: [Resource_Show::resource_show()]).
|
||||
|
||||
%%
|
||||
-export_type([
|
||||
resource_subids/0,
|
||||
resources_subids/0
|
||||
]).
|
||||
|
||||
-type(resource_subids()
|
||||
:: {Resource :: xmpp_jid:resource_jid(),
|
||||
SubIds :: [SubId::exmpp_pubsub:subId(),...]}
|
||||
).
|
||||
|
||||
-type(resources_subids() :: [Resource_SubIds::resource_subids(),...]).
|
||||
|
||||
%%%
|
||||
-export_type([
|
||||
entity/0,
|
||||
n0de/0,
|
||||
cache/0,
|
||||
subids/0,
|
||||
event/0
|
||||
]).
|
||||
|
||||
-type(entity() :: #entity{}).
|
||||
% id :: xmpp_jid:usr_bare(),
|
||||
% affiliation :: 'member' | 'owner' | 'publisher',
|
||||
% subscriptions :: []%[exmpp_pubsub:subscription(),...]
|
||||
%}).
|
||||
|
||||
%%%
|
||||
-type(n0de() :: #node{}).
|
||||
% id :: exmpp_pubsub:nodeId(),
|
||||
% owners :: [Node_Owner::xmpp_jid:usr_bare(),...],
|
||||
% access_model :: pubsub_options:access_model(),
|
||||
% itemreply :: 'owner' | 'publisher',
|
||||
% notification_type :: 'headline' | 'normal',
|
||||
% presence_based_delivery :: boolean(),
|
||||
% rosters_groups_allowed :: [] | pubsub_options:rosters_groups_allowed()
|
||||
%}).
|
||||
|
||||
%%%
|
||||
-type(cache() :: #cache{}).
|
||||
% presence :: undefined | mod_pubsub_dev:presence_cache(),
|
||||
% presence_subscriptions :: undefined | boolean(),
|
||||
% rosters_groups :: undefined | boolean()
|
||||
%}).
|
||||
|
||||
%%%
|
||||
-type(subids() :: #subids{}).
|
||||
% presence :: undefined | [] | mod_pubsub_dev:resources_subids(),
|
||||
% no_presence :: undefined | [] | mod_pubsub_dev:resources_subids()
|
||||
%}).
|
||||
|
||||
%%
|
||||
-type(event() :: #event{
|
||||
% host :: xmpp_jid:raw_jid_component_bare(),
|
||||
% component :: xmpp_jid:component_bare(),
|
||||
% entity :: mod_pubsub_dev:entity(),
|
||||
% node :: mod_pubsub_dev:n0de(),
|
||||
% cache :: mod_pubsub_dev:cache(),
|
||||
% subids :: mod_pubsub_dev:subids()
|
||||
}).
|
||||
|
||||
%%%
|
||||
-export_type([
|
||||
item/0,
|
||||
published_item/0,
|
||||
retracted_item/0
|
||||
]).
|
||||
|
||||
-type(published_item() :: #item{
|
||||
access_model :: undefined | pubsub_options:access_model(),
|
||||
presence_based_delivery :: undefined | boolean(),
|
||||
rosters_groups_allowed :: [] | pubsub_options:rosters_groups_allowed(),
|
||||
stanza :: xmlel()
|
||||
}).
|
||||
|
||||
-type(retracted_item() :: #item{
|
||||
access_model :: undefined | pubsub_options:access_model(),
|
||||
presence_based_delivery :: undefined | boolean(),
|
||||
rosters_groups_allowed :: [] | pubsub_options:rosters_groups_allowed(),
|
||||
stanza :: xmlel()
|
||||
}).
|
||||
|
||||
-type(item() :: published_item() | retracted_item()).
|
||||
|
||||
|
||||
%%
|
||||
|
||||
-export_type([
|
||||
pubsub_itemId/0,
|
||||
pubsub_nodeId/0,
|
||||
pubsub_stateId/0,
|
||||
item_owners/0,
|
||||
node_owners/0,
|
||||
item_creation/0,
|
||||
item_modification/0,
|
||||
node_creation/0
|
||||
]).
|
||||
|
||||
-type(pubsub_itemId()
|
||||
:: {ItemId::exmpp_pubsub:itemId(), NodeIdx::exmpp_pubsub:nodeIdx()}
|
||||
).
|
||||
|
||||
-type(pubsub_nodeId()
|
||||
:: {Pubsub_Host :: exmpp_pubsub:host(), NodeId :: exmpp_pubsub:nodeId()}
|
||||
).
|
||||
|
||||
-type(pubsub_stateId()
|
||||
:: {Entity::xmpp_jid:usr_bare(), NodeIdx::exmpp_pubsub:nodeIdx()}
|
||||
).
|
||||
|
||||
-type(item_owners() :: [Entity::xmpp_jid:usr_bare(),...]).
|
||||
-type(node_owners() :: [Entity::xmpp_jid:usr_bare(),...]).
|
||||
|
||||
-type(item_creation()
|
||||
:: {DateTime::erlang:timestamp(), Entity::xmpp_jid:usr_entity()}
|
||||
).
|
||||
|
||||
-type(item_modification()
|
||||
:: {DateTime::erlang:timestamp(), Entity::xmpp_jid:usr_entity()}
|
||||
).
|
||||
|
||||
-type(node_creation()
|
||||
:: {DateTime::erlang:timestamp(), Entity::xmpp_jid:usr_entity()}
|
||||
).
|
||||
|
||||
|
||||
|
||||
%%
|
||||
-export_type([
|
||||
pubsub_state/0,
|
||||
pubsub_states/0,
|
||||
%
|
||||
pubsub_state_owner/0,
|
||||
pubsub_state_publisher/0,
|
||||
pubsub_state_publish_only/0,
|
||||
pubsub_state_member/0,
|
||||
pubsub_state_none/0,
|
||||
pubsub_state_outcast/0
|
||||
]).
|
||||
|
||||
-type(pubsub_state_owner()
|
||||
:: #pubsub_state_dev{
|
||||
id :: mod_pubsub_dev:pubsub_stateId(),
|
||||
nodeidx :: exmpp_pubsub:nodeIdx(),
|
||||
affiliation :: 'owner',
|
||||
access :: undefined | 'presence' | 'roster',
|
||||
%subscriptions :: [exmpp_pubsub:subscription_subscribed() |
|
||||
% exmpp_pubsub:subscription_unconfigured()],
|
||||
subscriptions :: [exmpp_pubsub:subscription()],
|
||||
itemids :: [] | exmpp_pubsub:itemIds()
|
||||
}
|
||||
).
|
||||
|
||||
%%
|
||||
-type(pubsub_state_publisher()
|
||||
:: #pubsub_state_dev{
|
||||
id :: mod_pubsub_dev:pubsub_stateId(),
|
||||
nodeidx :: exmpp_pubsub:nodeIdx(),
|
||||
affiliation :: 'publisher',
|
||||
access :: undefined | 'presence' | 'roster',
|
||||
%subscriptions :: [exmpp_pubsub:subscription_subscribed() |
|
||||
% exmpp_pubsub:subscription_unconfigured()],
|
||||
subscriptions :: [exmpp_pubsub:subscription()],
|
||||
itemids :: [] | exmpp_pubsub:itemIds()
|
||||
}
|
||||
).
|
||||
|
||||
%%
|
||||
-type(pubsub_state_publish_only()
|
||||
:: #pubsub_state_dev{
|
||||
id :: mod_pubsub_dev:pubsub_stateId(),
|
||||
nodeidx :: exmpp_pubsub:nodeIdx(),
|
||||
affiliation :: 'publish-only',
|
||||
access :: undefined | 'presence' | 'roster',
|
||||
subscriptions :: [],
|
||||
itemids :: [] | exmpp_pubsub:itemIds()
|
||||
}
|
||||
).
|
||||
|
||||
%%
|
||||
-type(pubsub_state_member()
|
||||
:: #pubsub_state_dev{
|
||||
id :: mod_pubsub_dev:pubsub_stateId(),
|
||||
nodeidx :: exmpp_pubsub:nodeIdx(),
|
||||
affiliation :: 'member',
|
||||
access :: undefined | 'pending' | 'presence' | 'roster',
|
||||
subscriptions :: [],
|
||||
itemids :: [] | exmpp_pubsub:itemIds()
|
||||
}
|
||||
%%
|
||||
| #pubsub_state_dev{
|
||||
id :: mod_pubsub_dev:pubsub_stateId(),
|
||||
nodeidx :: exmpp_pubsub:nodeIdx(),
|
||||
affiliation :: 'member',
|
||||
access :: undefined | 'pending' | 'presence' | 'roster',
|
||||
%subscriptions :: [exmpp_pubsub:subscription_pending(),...],
|
||||
subscriptions :: [exmpp_pubsub:subscription()],
|
||||
itemids :: [] | exmpp_pubsub:itemIds()
|
||||
}
|
||||
%%
|
||||
| #pubsub_state_dev{
|
||||
id :: mod_pubsub_dev:pubsub_stateId(),
|
||||
nodeidx :: exmpp_pubsub:nodeIdx(),
|
||||
affiliation :: 'member',
|
||||
subscriptions :: [exmpp_pubsub:subscription()],
|
||||
%subscriptions :: [exmpp_pubsub:subscription_pending() |
|
||||
% exmpp_pubsub:subscription_subscribed() |
|
||||
% exmpp_pubsub:subscription_unconfigured()],
|
||||
itemids :: [] | exmpp_pubsub:itemIds()
|
||||
}
|
||||
).
|
||||
|
||||
%%
|
||||
-type(pubsub_state_none()
|
||||
:: #pubsub_state_dev{
|
||||
id :: mod_pubsub_dev:pubsub_stateId(),
|
||||
nodeidx :: exmpp_pubsub:nodeIdx(),
|
||||
affiliation :: 'none',
|
||||
access :: undefined | 'presence' | 'roster',
|
||||
subscriptions :: [],
|
||||
itemids :: []
|
||||
}
|
||||
%%
|
||||
| #pubsub_state_dev{
|
||||
id :: mod_pubsub_dev:pubsub_stateId(),
|
||||
nodeidx :: exmpp_pubsub:nodeIdx(),
|
||||
affiliation :: 'none',
|
||||
access :: undefined | 'presence' | 'roster',
|
||||
subscriptions :: [],
|
||||
itemids :: exmpp_pubsub:itemIds()
|
||||
}
|
||||
%%
|
||||
| #pubsub_state_dev{
|
||||
id :: mod_pubsub_dev:pubsub_stateId(),
|
||||
nodeidx :: exmpp_pubsub:nodeIdx(),
|
||||
affiliation :: 'none',
|
||||
access :: undefined | 'presence' | 'roster',
|
||||
subscriptions :: [],
|
||||
itemids :: exmpp_pubsub:itemIds()
|
||||
}
|
||||
).
|
||||
|
||||
%%
|
||||
-type(pubsub_state_outcast()
|
||||
:: #pubsub_state_dev{
|
||||
id :: mod_pubsub_dev:pubsub_stateId(),
|
||||
nodeidx :: exmpp_pubsub:nodeIdx(),
|
||||
affiliation :: 'outcast',
|
||||
access :: undefined | 'presence' | 'roster',
|
||||
subscriptions :: [exmpp_pubsub:subscription()],
|
||||
%subscriptions :: [exmpp_pubsub:subscription_pending() |
|
||||
% exmpp_pubsub:subscription_subscribed() |
|
||||
% exmpp_pubsub:subscription_unconfigured()],
|
||||
itemids :: [] | exmpp_pubsub:itemIds()
|
||||
}
|
||||
).
|
||||
|
||||
|
||||
%%
|
||||
-type(pubsub_state() :: mod_pubsub_dev:pubsub_state_owner()
|
||||
| mod_pubsub_dev:pubsub_state_publisher()
|
||||
| mod_pubsub_dev:pubsub_state_publish_only()
|
||||
| mod_pubsub_dev:pubsub_state_member()
|
||||
| mod_pubsub_dev:pubsub_state_none()
|
||||
| mod_pubsub_dev:pubsub_state_outcast()
|
||||
).
|
||||
|
||||
-type(pubsub_states() :: [Pubsub_State::mod_pubsub_dev:pubsub_state(),...]).
|
||||
|
||||
|
||||
%%
|
||||
-export_type([
|
||||
pubsub_node/0,
|
||||
pubsub_nodes/0
|
||||
]).
|
||||
|
||||
-type(pubsub_node()
|
||||
:: #pubsub_node_dev{
|
||||
id :: mod_pubsub_dev:pubsub_nodeId(),
|
||||
idx :: exmpp_pubsub:nodeIdx(),
|
||||
creation :: mod_pubsub_dev:node_creation(),
|
||||
level :: exmpp_pubsub:level(),
|
||||
owners :: mod_pubsub_dev:node_owners(),
|
||||
itemids :: [] | exmpp_pubsub:itemIds(),
|
||||
options :: pubsub_options:options_node()
|
||||
}
|
||||
).
|
||||
|
||||
-type(pubsub_nodes() :: [Pubsub_Node::mod_pubsub_dev:pubsub_node(),...]).
|
||||
|
||||
|
||||
%%
|
||||
-export_type([
|
||||
pubsub_item/0,
|
||||
pubsub_items/0
|
||||
]).
|
||||
|
||||
-type(pubsub_item()
|
||||
:: #pubsub_item_dev{
|
||||
id :: mod_pubsub_dev:pubsub_itemId(),
|
||||
nodeidx :: exmpp_pubsub:nodeIdx(),
|
||||
owners :: mod_pubsub_dev:item_owners(),
|
||||
creation :: mod_pubsub_dev:item_creation(),
|
||||
modification :: mod_pubsub_dev:item_modification(),
|
||||
payload :: exmpp_pubsub:payload(),
|
||||
options :: [] | pubsub_options:options_item()
|
||||
}
|
||||
).
|
||||
|
||||
-type(pubsub_items() :: [Pubsub_Item::mod_pubsub_dev:pubsub_item(),...]).
|
||||
|
||||
%%
|
||||
-export_type([
|
||||
pubsub_last_item/0
|
||||
]).
|
||||
|
||||
-type(pubsub_last_item()
|
||||
:: #pubsub_last_item_dev{
|
||||
nodeidx :: exmpp_pubsub:nodeIdx(),
|
||||
id :: exmpp_pubsub:itemId(),
|
||||
owners :: mod_pubsub_dev:item_owners(),
|
||||
creation :: mod_pubsub_dev:item_creation(),
|
||||
payload :: exmpp_pubsub:payload(),
|
||||
options :: [] | pubsub_options:options_item()
|
||||
}
|
||||
).
|
||||
|
||||
%%
|
||||
-export_type([
|
||||
pubsub_subscription_pending/0
|
||||
]).
|
||||
|
||||
-type(pubsub_subscription_pending()
|
||||
:: #pubsub_subscription_pending{
|
||||
id :: {Entity::xmpp_jid:usr_bare(), NodeIdx::exmpp_pubsub:nodeIdx()},
|
||||
nodeidx :: exmpp_pubsub:nodeIdx(),
|
||||
subids :: [SubId::exmpp_pubsub:subId(),...]
|
||||
}
|
||||
).
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-define(PROCNAME, ejabberd_mod_pubsub_dev).
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-record(state,
|
||||
{
|
||||
host :: xmpp_jid:raw_jid_component_bare(),
|
||||
pubsub_host :: xmpp_jid:raw_jid_component_bare(),
|
||||
pubsub :: #capabilities{},
|
||||
pubsub_on_jid :: #capabilities{}
|
||||
}).
|
||||
|
||||
-type(state()
|
||||
:: #state{
|
||||
host :: xmpp_jid:raw_jid_component_bare(),
|
||||
pubsub_host :: xmpp_jid:raw_jid_component_bare(),
|
||||
pubsub :: #capabilities{},
|
||||
pubsub_on_jid :: #capabilities{}
|
||||
}
|
||||
).
|
||||
|
||||
|
||||
%%====================================================================
|
||||
%% API
|
||||
%%====================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
|
||||
%% Description: Starts the server
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%% @spec start_link(Host, Options) -> {'ok', pid()} | 'ignore' | {'error', atom()}
|
||||
%% Host = string()
|
||||
%% Options = {Option::atom(), Value::term()}
|
||||
-spec(start_link/2 ::
|
||||
(
|
||||
Host :: string(),
|
||||
Options :: [Option::{Key::atom(), Value::term()}])
|
||||
-> {'ok', pid()} | 'ignore' | {'error', _}
|
||||
).
|
||||
|
||||
start_link(Host, Options) ->
|
||||
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||
gen_server:start_link({local, Proc}, ?MODULE, [Host, Options], []).
|
||||
|
||||
%% @spec start(Host, Options) -> {'error',atom()} | {'ok','undefined' | pid()} | {'ok','undefined' | pid(),any()}
|
||||
%% Host = string()
|
||||
%% Options = {Option::atom(), Value::term()}
|
||||
-spec(start/2 ::
|
||||
(
|
||||
Host :: string(),
|
||||
Options :: [Option::{Key::atom(), Value::term()}])
|
||||
-> {'error',_} | {'ok','undefined' | pid()} | {'ok','undefined' | pid(),_}
|
||||
).
|
||||
|
||||
start(Host, Options) ->
|
||||
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||
ChildSpec = {Proc,
|
||||
{?MODULE, start_link, [Host, Options]},
|
||||
transient, 1000, worker, [?MODULE]},
|
||||
supervisor:start_child(ejabberd_sup, ChildSpec).
|
||||
|
||||
%% @spec stop(Host) -> 'ok' | {'error','not_found' | 'running' | 'simple_one_for_one'}
|
||||
%% Host = string()
|
||||
-spec(stop/1 ::
|
||||
(
|
||||
Host :: string())
|
||||
-> 'ok' | {'error','not_found' | 'running' | 'simple_one_for_one'}
|
||||
).
|
||||
|
||||
stop(Host) ->
|
||||
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||
gen_server:call(Proc, stop),
|
||||
supervisor:delete_child(ejabberd_sup, Proc).
|
||||
|
||||
|
||||
|
||||
|
||||
%%====================================================================
|
||||
%% gen_server callbacks
|
||||
%%====================================================================
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Function: init(Args) -> {ok, State} |
|
||||
%% {ok, State, Timeout} |
|
||||
%% ignore |
|
||||
%% {stop, Reason}
|
||||
%% Description: Initiates the server
|
||||
%%--------------------------------------------------------------------
|
||||
-spec(init/1 ::
|
||||
(
|
||||
Args :: [binary() | [{Option::atom(), Value::term()}]])
|
||||
-> {'ok', State::state()}
|
||||
).
|
||||
|
||||
init([Host, Options] = _Args) ->
|
||||
?DEBUG("pubsub init ~p ~p",[Host, Options]),
|
||||
Pubsub_Host = gen_mod:expand_host_name(Host, Options, <<"pubsub">>),
|
||||
IQDisc = gen_mod:get_opt('iqdisc', Options, 'one_queue'),
|
||||
|
||||
% mod_disco:register_feature(Server_HostB, ?NS_PUBSUB_s),
|
||||
%%
|
||||
%% Pubsub Hooks
|
||||
%% - Service disco hooks
|
||||
%% * disco_local_identity
|
||||
%% * disco_local_features
|
||||
%% * disco_local_items
|
||||
%% * disco_local_forms
|
||||
%% - Connectivity hooks
|
||||
%% * presence_probe_hook
|
||||
%% * sm_remove_connection_hook
|
||||
%% - Roster hooks
|
||||
%% * roster_in_subscription
|
||||
%% * roster_out_subscription
|
||||
%% - User managment hooks
|
||||
%% * remove_user
|
||||
%% * anonymous_purge_hook
|
||||
%%
|
||||
%% Pubsub On Jid hooks
|
||||
%% - Service disco hooks
|
||||
%% * disco_sm_identity
|
||||
%% * disco_sm_features
|
||||
%% * disco_sm_items
|
||||
%% * disco_sm_forms
|
||||
%% - Connectitivy
|
||||
%% * caps_update
|
||||
|
||||
|
||||
Pubsub_Features = node_flat_dev:pubsub_features(),
|
||||
% mod_disco:register_feature(Server_HostB, ?NS_PUBSUB_s),
|
||||
pubsub_db:init('mnesia', 'dev'),
|
||||
%% Register hooks according to available Pubsub Features
|
||||
register_hooks(Host, Pubsub_Features, pubsub_hooks),
|
||||
%%
|
||||
ejabberd_router:register_route(Pubsub_Host),
|
||||
{ok,
|
||||
#state{
|
||||
host = Host,
|
||||
pubsub_host = Pubsub_Host,
|
||||
pubsub = node_flat_dev:capabilities()
|
||||
}
|
||||
}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Function:
|
||||
%% handle_call(Request, From, State) -> {reply, Reply, State} |
|
||||
%% {reply, Reply, State, Timeout} |
|
||||
%% {noreply, State} |
|
||||
%% {noreply, State, Timeout} |
|
||||
%% {stop, Reason, Reply, State} |
|
||||
%% {stop, Reason, State}
|
||||
%% Description: Handling call messages
|
||||
%%--------------------------------------------------------------------
|
||||
%% @private
|
||||
|
||||
handle_call(stop, _From, State) ->
|
||||
{stop, normal, ok, State}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Function: handle_cast(Msg, State) -> {noreply, State} |
|
||||
%% {noreply, State, Timeout} |
|
||||
%% {stop, Reason, State}
|
||||
%% Description: Handling cast messages
|
||||
%%--------------------------------------------------------------------
|
||||
%% @private
|
||||
handle_cast(_Msg, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Function: handle_info(Info, State) -> {noreply, State} |
|
||||
%% {noreply, State, Timeout} |
|
||||
%% {stop, Reason, State}
|
||||
%% Description: Handling all non call/cast messages
|
||||
%%--------------------------------------------------------------------
|
||||
%% @private
|
||||
|
||||
handle_info({route, From, #jid{resource = undefined} = To, Stanza},
|
||||
#state{host = Host, pubsub = Capabilities} = State) ->
|
||||
do_route(Host, To, From, Stanza, Capabilities),
|
||||
{noreply, State};
|
||||
%%
|
||||
handle_info(_Info, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Function: terminate(Reason, State) -> void()
|
||||
%% Description: This function is called by a gen_server when it is about to
|
||||
%% terminate. It should be the opposite of Module:init/1 and do any necessary
|
||||
%% cleaning up. When it returns, the gen_server terminates with Reason.
|
||||
%% The return value is ignored.
|
||||
%%--------------------------------------------------------------------
|
||||
%% @private
|
||||
%% @todo : -spec
|
||||
-spec(terminate/2 ::
|
||||
(
|
||||
Reason :: _,
|
||||
State :: state())
|
||||
-> 'ok'
|
||||
).
|
||||
|
||||
terminate(_Reason, #state{host = Host, pubsub_host = Pubsub_Host}) ->
|
||||
ejabberd_router:unregister_route(Pubsub_Host),
|
||||
ok.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
|
||||
%% Description: Convert process state when code is changed
|
||||
%%--------------------------------------------------------------------
|
||||
%% @private
|
||||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
|
||||
%%
|
||||
-define(Is_Stanza_IQ(Stanza),
|
||||
(
|
||||
Stanza#xmlel.name == <<"iq">>
|
||||
)).
|
||||
|
||||
-define(Is_Stanza_Message(Stanza),
|
||||
(
|
||||
Stanza#xmlel.name == <<"message">>
|
||||
)).
|
||||
|
||||
-define(Is_Stanza_Presence(Stanza),
|
||||
(
|
||||
Stanza#xmlel.name == <<"presence">>
|
||||
)).
|
||||
|
||||
-define(Is_IQ_Ignore(IQ),
|
||||
(
|
||||
IQ#iq.type == 'result'
|
||||
orelse
|
||||
IQ#iq.type == 'error'
|
||||
)).
|
||||
|
||||
-define(Is_IQ_Pubsub(IQ),
|
||||
(
|
||||
(IQ#iq.type == 'set'
|
||||
orelse
|
||||
IQ#iq.type == 'get')
|
||||
andalso
|
||||
(IQ#iq.xmlns == ?NS_PUBSUB
|
||||
orelse
|
||||
IQ#iq.xmlns == ?NS_PUBSUB_OWNER)
|
||||
andalso
|
||||
IQ#iq.sub_el#xmlel.name == <<"pubsub">>
|
||||
)).
|
||||
|
||||
-define(Is_IQ_Get_Disco_Info(IQ),
|
||||
(
|
||||
IQ#iq.type == 'get'
|
||||
andalso
|
||||
IQ#iq.xmlns == ?NS_DISCO_INFO
|
||||
andalso
|
||||
IQ#iq.sub_el#xmlel.name == <<"query">>
|
||||
% andalso
|
||||
% IQ#iq.payload#xmlel.children == []
|
||||
)).
|
||||
|
||||
-define(Is_IQ_Get_Disco_Items(IQ),
|
||||
(
|
||||
IQ#iq.type == 'get'
|
||||
andalso
|
||||
IQ#iq.xmlns == ?NS_DISCO_ITEMS
|
||||
andalso
|
||||
IQ#iq.sub_el#xmlel.name == <<"query">>
|
||||
% andalso
|
||||
% IQ#iq.payload#xmlel.children == []
|
||||
)).
|
||||
|
||||
%%
|
||||
do_route(Host,
|
||||
#jid{lserver = Pubsub_Host} = Pubsub_Component,
|
||||
#jid{luser = U, lserver = S, lresource = R} = Entity, Stanza_IQ,
|
||||
#capabilities{privacy = Privacy, plugin = Plugin} = Capabilities)
|
||||
when ?Is_Stanza_IQ(Stanza_IQ) ->
|
||||
case IQ = jlib:iq_query_or_response_info(Stanza_IQ) of
|
||||
IQ when ?Is_IQ_Ignore(IQ) ->
|
||||
ok;
|
||||
IQ when ?Is_IQ_Get_Disco_Info(IQ) ->
|
||||
case
|
||||
pubsub_disco:iq_disco_info('dev', Host, Pubsub_Host,
|
||||
Privacy, {U,S,undefined},
|
||||
case S of
|
||||
Host -> 'local';
|
||||
_ -> 'remote'
|
||||
end,
|
||||
Plugin,
|
||||
case xml:get_tag_attr_s(<<"node">>, IQ#iq.sub_el) of
|
||||
<<>> -> undefined;
|
||||
NodeId -> NodeId
|
||||
end,
|
||||
xml:remove_cdata(IQ#iq.sub_el#xmlel.children))
|
||||
of
|
||||
{result, Xmlel_Query} ->
|
||||
ejabberd_router:route(Pubsub_Component, Entity,
|
||||
jlib:iq_to_xml(IQ#iq{
|
||||
type = result,
|
||||
sub_el = [Xmlel_Query]
|
||||
}));
|
||||
{error, Error} ->
|
||||
ejabberd_router:route(Pubsub_Component, Entity,
|
||||
jlib:make_error_reply(Stanza_IQ, Error))
|
||||
end;
|
||||
IQ when ?Is_IQ_Get_Disco_Items(IQ) ->
|
||||
case
|
||||
pubsub_disco:iq_disco_items('dev', Host, Pubsub_Host,
|
||||
Privacy, {U,S,undefined},
|
||||
case S of
|
||||
Host -> 'local';
|
||||
_ -> 'remote'
|
||||
end,
|
||||
Plugin,
|
||||
case xml:get_tag_attr_s(<<"node">>, IQ#iq.sub_el) of
|
||||
<<>> -> undefined;
|
||||
NodeId -> NodeId
|
||||
end,
|
||||
xml:remove_cdata(IQ#iq.sub_el#xmlel.children))
|
||||
of
|
||||
{result, Xmlel_Query} ->
|
||||
ejabberd_router:route(Pubsub_Component, Entity,
|
||||
jlib:iq_to_xml(IQ#iq{
|
||||
type = result,
|
||||
sub_el = [Xmlel_Query]
|
||||
}));
|
||||
{error, Error} ->
|
||||
ejabberd_router:route(Pubsub_Component, Entity,
|
||||
jlib:make_error_reply(Stanza_IQ, Error))
|
||||
end;
|
||||
IQ when ?Is_IQ_Pubsub(IQ) ->
|
||||
case
|
||||
iq_pubsub(Host, Pubsub_Host, {U,S,R}, IQ#iq.type,
|
||||
_Rsm = lists:member(?NS_RSM, Plugin:features()),
|
||||
xml:remove_cdata(IQ#iq.sub_el#xmlel.children),
|
||||
IQ#iq.lang, Capabilities)
|
||||
of
|
||||
{result, []} ->
|
||||
ejabberd_router:route(Pubsub_Component, Entity,
|
||||
jlib:iq_to_xml(IQ#iq{
|
||||
type = result,
|
||||
sub_el = []
|
||||
}));
|
||||
{result, Xmlels} ->
|
||||
ejabberd_router:route(Pubsub_Component, Entity,
|
||||
jlib:iq_to_xml(IQ#iq{
|
||||
type = result,
|
||||
sub_el = Xmlels
|
||||
}));
|
||||
{error, Error} ->
|
||||
ejabberd_router:route(Pubsub_Component, Entity,
|
||||
jlib:make_error_reply(Stanza_IQ, Error))
|
||||
end
|
||||
end;
|
||||
do_route(Host,
|
||||
#jid{lserver = Pubsub_Host} = Pubsub_Component,
|
||||
#jid{luser = U, lserver = S, lresource = R} = Entity, Stanza_Message,
|
||||
Capabilities)
|
||||
when ?Is_Stanza_Message(Stanza_Message) ->
|
||||
ok;
|
||||
do_route(Host,
|
||||
#jid{lserver = Pubsub_Host} = Pubsub_Component,
|
||||
#jid{luser = U, lserver = S, lresource = R} = Entity, Stanza_Presence,
|
||||
Capabilities)
|
||||
when ?Is_Stanza_Presence(Stanza_Presence) ->
|
||||
ok.
|
||||
|
||||
|
||||
iq_pubsub(Host, Pubsub_Host, Entity, IQ_Type, Rsm, Xmlels, _Lang,
|
||||
#capabilities{api = #api{parser = Parser, core = API_Core}} = Capabilities) ->
|
||||
case Parser:parse(IQ_Type, Xmlels, Rsm, API_Core) of
|
||||
{result, Module, Function, Parameters} ->
|
||||
Module:Function(Host, Pubsub_Host, Entity, Parameters, Capabilities);
|
||||
Error ->
|
||||
Error
|
||||
end.
|
||||
|
||||
|
||||
|
||||
register_hooks(Host, Pubsub_Features, Module) ->
|
||||
register_hooks('roster', Host, Pubsub_Features, Module),
|
||||
register_hooks('presence', Host, Pubsub_Features, Module).
|
||||
|
||||
%ejabberd_hooks:add(roster_in_subscription, Host, pubsub_hooks, roster_in_subscription, 50),
|
||||
%ejabberd_hooks:add(roster_out_subscription, Host, ?MODULE, roster_out_subscription, 50),
|
||||
%ejabberd_hooks:add(roster_get, Host, ?MODULE, roster_get, 50),
|
||||
%ejabberd_hooks:add(roster_get_jid_info, Host, ?MODULE, roster_get_jid_info, 50),
|
||||
%ejabberd_hooks:add(roster_get_subscription_lists, Host, ?MODULE, roster_get_subscription_lists, 50),
|
||||
%%ejabberd_hooks:add(roster_process_item, Host, pubsub_hooks, roster_process_item, 50).
|
||||
|
||||
|
||||
register_hooks('roster', Host, Pubsub_Features, Module) ->
|
||||
case lists:member("access-roster", Pubsub_Features) of
|
||||
true ->
|
||||
ejabberd_hooks:add(roster_process_item, Host, Module,
|
||||
roster_process_item, 50),
|
||||
ok;
|
||||
false ->
|
||||
ok
|
||||
end;
|
||||
%%
|
||||
register_hooks('presence', Host, Pubsub_Features, Module) ->
|
||||
case
|
||||
lists:member(<<"access-presence">>, Pubsub_Features)
|
||||
orelse
|
||||
lists:member(<<"last-published">>, Pubsub_Features)
|
||||
orelse
|
||||
lists:member(<<"leased-subscription">>, Pubsub_Features)
|
||||
orelse
|
||||
lists:member(<<"presence-notifications">>, Pubsub_Features)
|
||||
of
|
||||
true ->
|
||||
ejabberd_hooks:add(presence_probe_hook, Host, Module,
|
||||
presence_online, 80),
|
||||
ejabberd_hooks:add(sm_remove_connection_hook, Host, Module,
|
||||
presence_offline, 80),
|
||||
ok;
|
||||
false ->
|
||||
ok
|
||||
end.
|
||||
|
||||
|
||||
roster_get(Acc, {User, Server}) ->
|
||||
?INFO_MSG("ROSTER_GET Acc ~p ~nUser ~p ~nServer ~p ~n",
|
||||
[Acc, User, Server]).
|
||||
|
||||
roster_get_jid_info(Acc, User, Server, JID) ->
|
||||
?INFO_MSG("ROSTER_GET_JID_INFO Acc ~p ~nUser ~p ~nServer ~p ~nJID ~p ~n",
|
||||
[Acc, User, Server, JID]).
|
||||
|
||||
roster_get_subscription_lists(Acc, User, Server) ->
|
||||
?INFO_MSG("ROSTER_GET_SUBSCRIPTION_LISTS Acc ~p ~nUser ~p ~nServer ~p ~n",
|
||||
[Acc, User, Server]).
|
||||
|
||||
roster_in_subscription(User, Server, JID, SubscriptionType, Reason, A) ->
|
||||
?INFO_MSG("ROSTER_IN_SUBSCRITION User ~p ~n Server ~p ~n JID ~p ~n SubscriptionType ~p ~n, Reason ~p ~nA ~p ~n",
|
||||
[User, Server, JID, SubscriptionType, Reason, A]).
|
||||
|
||||
roster_out_subscription(User, Server, JID, SubscriptionType) ->
|
||||
?INFO_MSG("ROSTER_OUT_SUBSCRITION User ~p ~n Server ~p ~n JID ~p ~n SubscriptionType ~p ~n",
|
||||
[User, Server, JID, SubscriptionType]).
|
||||
|
||||
roster_process_item(RosterItem, Server) ->
|
||||
?INFO_MSG("ROSTER_PROCESS_ITEM RosterItem ~p ~nServer ~p ~n",
|
||||
[RosterItem, Server]),
|
||||
RosterItem.
|
||||
|
||||
@@ -0,0 +1,310 @@
|
||||
%%% ====================================================================
|
||||
%%% ``The contents of this file are subject to the Erlang Public License,
|
||||
%%% Version 1.1, (the "License"); you may not use this file except in
|
||||
%%% compliance with the License. You should have received a copy of the
|
||||
%%% Erlang Public License along with this software. If not, it can be
|
||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||
%%%
|
||||
%%% Software distributed under the License is distributed on an "AS IS"
|
||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
%%% the License for the specific language governing rights and limitations
|
||||
%%% under the License.
|
||||
%%%
|
||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
||||
%%% Portions created by ProcessOne are Copyright 2006-2013, ProcessOne
|
||||
%%% All Rights Reserved.''
|
||||
%%% This software is copyright 2006-2013, ProcessOne.
|
||||
%%%
|
||||
%%% @copyright 2006-2013 ProcessOne
|
||||
%%% @author Karim Gemayel <karim.gemayel@process-one.net>
|
||||
%%% [http://www.process-one.net/]
|
||||
%%% @version {@vsn}, {@date} {@time}
|
||||
%%% @end
|
||||
%%% ====================================================================
|
||||
|
||||
%%% @headerfile "pubsub_dev.hrl"
|
||||
|
||||
-module(node_flat_dev).
|
||||
-author('karim.gemayel@process-one.net').
|
||||
|
||||
-include("pubsub_dev.hrl").
|
||||
-include("pubsub_api.hrl").
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
|
||||
|
||||
%%
|
||||
-spec(capabilities/0 :: () -> #capabilities{}).
|
||||
|
||||
capabilities() ->
|
||||
#capabilities{plugin = ?MODULE}.
|
||||
|
||||
|
||||
%%
|
||||
-spec(pubsub_features/0 :: () -> Pubsub_Features::exmpp_pubsub:pubsub_features()).
|
||||
|
||||
pubsub_features() ->
|
||||
[<<"access-authorize">>,
|
||||
<<"access-open">>,
|
||||
<<"access-presence">>,
|
||||
<<"access-roster">>,
|
||||
<<"access-whitelist">>,
|
||||
<<"auto-create">>,
|
||||
<<"auto-subscribe">>,
|
||||
%<<"collections">>,
|
||||
<<"config-node">>,
|
||||
<<"create-and-configure">>,
|
||||
<<"create-nodes">>,
|
||||
<<"delete-items">>,
|
||||
<<"delete-nodes">>,
|
||||
%<<"filtered-notifications">>,
|
||||
<<"get-pending">>,
|
||||
<<"instant-nodes">>,
|
||||
<<"item-ids">>,
|
||||
<<"last-published">>,
|
||||
<<"leased-subscription">>,
|
||||
<<"manage-subscriptions">>,
|
||||
<<"member-affiliation">>,
|
||||
<<"meta-data">>,
|
||||
<<"modify-affiliations">>,
|
||||
%<<"multi-collections">>,
|
||||
<<"multi-subscribe">>,
|
||||
<<"outcast-affiliation">>,
|
||||
<<"persistent-items">>,
|
||||
<<"presence-notifications">>,
|
||||
%"presence-subscribe">>,
|
||||
<<"publish">>,
|
||||
<<"publish-only-affiliation">>,
|
||||
<<"publish-options">>,
|
||||
<<"publisher-affiliation">>,
|
||||
<<"purge-nodes">>,
|
||||
<<"retract-items">>,
|
||||
<<"retrieve-affiliations">>,
|
||||
<<"retrieve-default">>,
|
||||
<<"retrieve-default-sub">>,
|
||||
<<"retrieve-items">>,
|
||||
<<"retrieve-subscriptions">>,
|
||||
<<"subscribe">>,
|
||||
<<"subscription-notifications">>,
|
||||
<<"subscription-options">>].
|
||||
|
||||
%%
|
||||
-spec(pubsub_features/1 ::
|
||||
(
|
||||
Entity_Type :: 'local' | 'remote')
|
||||
-> Pubsub_Features::exmpp_pubsub:pubsub_features()
|
||||
).
|
||||
|
||||
pubsub_features('local') ->
|
||||
[<<"access-authorize">>,
|
||||
<<"access-open">>,
|
||||
<<"access-presence">>,
|
||||
<<"access-roster">>,
|
||||
<<"access-whitelist">>,
|
||||
<<"auto-create">>,
|
||||
<<"auto-subscribe">>,
|
||||
%<<"collections">>,
|
||||
<<"config-node">>,
|
||||
<<"create-and-configure">>,
|
||||
<<"create-nodes">>,
|
||||
<<"delete-items">>,
|
||||
<<"delete-nodes">>,
|
||||
%<<"filtered-notifications">>,
|
||||
<<"get-pending">>,
|
||||
<<"instant-nodes">>,
|
||||
<<"item-ids">>,
|
||||
<<"last-published">>,
|
||||
<<"leased-subscription">>,
|
||||
<<"manage-subscriptions">>,
|
||||
<<"member-affiliation">>,
|
||||
<<"meta-data">>,
|
||||
<<"modify-affiliations">>,
|
||||
%<<"multi-collections">>,
|
||||
<<"multi-subscribe">>,
|
||||
<<"outcast-affiliation">>,
|
||||
<<"persistent-items">>,
|
||||
<<"presence-notifications">>,
|
||||
%<<"presence-subscribe">>,
|
||||
<<"publish">>,
|
||||
<<"publish-only-affiliation">>,
|
||||
<<"publish-options">>,
|
||||
<<"publisher-affiliation">>,
|
||||
<<"purge-nodes">>,
|
||||
<<"retract-items">>,
|
||||
<<"retrieve-affiliations">>,
|
||||
<<"retrieve-default">>,
|
||||
<<"retrieve-default-sub">>,
|
||||
<<"retrieve-items">>,
|
||||
<<"retrieve-subscriptions">>,
|
||||
<<"subscribe">>,
|
||||
<<"subscription-notifications">>,
|
||||
<<"subscription-options">>];
|
||||
%%
|
||||
pubsub_features('remote') ->
|
||||
[<<"access-authorize">>,
|
||||
<<"access-open">>,
|
||||
<<"access-presence">>,
|
||||
<<"access-roster">>,
|
||||
<<"access-whitelist">>,
|
||||
<<"auto-create">>,
|
||||
<<"auto-subscribe">>,
|
||||
%<<"collections">>,
|
||||
<<"config-node">>,
|
||||
<<"create-and-configure">>,
|
||||
<<"create-nodes">>,
|
||||
<<"delete-items">>,
|
||||
<<"delete-nodes">>,
|
||||
%<<"filtered-notifications">>,
|
||||
<<"get-pending">>,
|
||||
<<"instant-nodes">>,
|
||||
<<"item-ids">>,
|
||||
<<"last-published">>,
|
||||
%<<"leased-subscription">>,
|
||||
<<"manage-subscriptions">>,
|
||||
<<"member-affiliation">>,
|
||||
<<"meta-data">>,
|
||||
<<"modify-affiliations">>,
|
||||
%<<"multi-collections">>,
|
||||
<<"multi-subscribe">>,
|
||||
<<"outcast-affiliation">>,
|
||||
<<"persistent-items">>,
|
||||
<<"publish">>,
|
||||
<<"publish-only-affiliation">>,
|
||||
<<"publish-options">>,
|
||||
<<"publisher-affiliation">>,
|
||||
<<"purge-nodes">>,
|
||||
<<"retract-items">>,
|
||||
<<"retrieve-affiliations">>,
|
||||
<<"retrieve-default">>,
|
||||
<<"retrieve-default-sub">>,
|
||||
<<"retrieve-items">>,
|
||||
<<"retrieve-subscriptions">>,
|
||||
<<"subscribe">>,
|
||||
<<"subscription-notifications">>,
|
||||
<<"subscription-options">>].
|
||||
|
||||
%%
|
||||
%%
|
||||
-spec(node_options/1 ::
|
||||
(
|
||||
Node_Type :: 'leaf' | 'collection')
|
||||
-> Node_Options :: pubsub_options:options_node_leaf()
|
||||
| pubsub_options:options_node_collection()
|
||||
).
|
||||
|
||||
node_options('leaf') ->
|
||||
[{'access_model', open},
|
||||
{'contact', []},
|
||||
%{'collection', []},
|
||||
{'deliver_notifications', true},
|
||||
{'deliver_payloads', true},
|
||||
{'description', undefined},
|
||||
{'item_expire', undefined},
|
||||
{'itemreply', publisher},
|
||||
{'language', <<"en">>},
|
||||
{'max_items', 2},
|
||||
{'max_payload_size', undefined},
|
||||
{'node_type', leaf},
|
||||
{'notification_type', normal},
|
||||
{'notify_config', true},
|
||||
{'notify_delete', true},
|
||||
{'notify_retract', true},
|
||||
{'notify_sub', true},
|
||||
{'persist_items', true},
|
||||
{'presence_based_delivery', true},
|
||||
{'publish_model', open},
|
||||
{'purge_offline', false},
|
||||
{'roster_groups_allowed', []},
|
||||
{'send_last_published_item', on_sub_and_presence},
|
||||
{'subscribe', true},
|
||||
{'tempsub', false},
|
||||
{'title', undefined},
|
||||
{'type', undefined}];
|
||||
%%
|
||||
node_options('collection') ->
|
||||
[].
|
||||
|
||||
item_options() ->
|
||||
[{'access_model', open},
|
||||
{'deliver_notifications', true},
|
||||
{'deliver_payloads', true},
|
||||
{'item_expire', undefined},
|
||||
{'itemreply', publisher},
|
||||
% {'max_payload_size', undefined},
|
||||
{'notification_type', normal},
|
||||
{'notify_config', true},
|
||||
{'notify_retract', true},
|
||||
{'persist_items', true},
|
||||
{'presence_based_delivery', true},
|
||||
% {'publish_model', open},
|
||||
{'purge_offline', false},
|
||||
{'roster_groups_allowed', []},
|
||||
{'send_last_published_item', on_sub_and_presence},
|
||||
{'type', undefined}].
|
||||
|
||||
%%
|
||||
-spec(subscription_options/2 ::
|
||||
(
|
||||
Entity_Type :: 'local' | 'remote',
|
||||
Node_Type :: 'leaf' | 'collection')
|
||||
-> Subscription_Options :: [] | pubsub_options:options_subscription()
|
||||
).
|
||||
|
||||
subscription_options('local', 'leaf') ->
|
||||
[];
|
||||
subscription_options('remote', 'leaf') ->
|
||||
[];
|
||||
subscription_options('local', 'collection') ->
|
||||
[];
|
||||
subscription_options('remote', 'collection') ->
|
||||
[].
|
||||
|
||||
%%
|
||||
-spec(default_subscription_options/2 ::
|
||||
(
|
||||
Entity_Type :: 'local' | 'remote',
|
||||
Node_Type :: 'leaf')%| 'collection')
|
||||
-> Subscription_Options :: pubsub_options:options_subscription_leaf()
|
||||
).
|
||||
|
||||
default_subscription_options('local', 'leaf') ->
|
||||
[{'deliver', true},
|
||||
{'expire', undefined},
|
||||
%{'include_body', undefined},
|
||||
{'show-values', ['away', 'chat', 'dnd', 'online', 'xa']}];
|
||||
%%
|
||||
default_subscription_options('remote', 'leaf') ->
|
||||
[{'deliver', true}
|
||||
%{'include_body', undefined}
|
||||
].
|
||||
%%
|
||||
%%default_subscription_options('local', 'collection') ->
|
||||
%% [{'deliver', true},
|
||||
%% %{'expire', undefined},
|
||||
%% %{'include_body', undefined},
|
||||
%% {'show-values', ['away', 'chat', 'dnd', 'online', 'xa']},
|
||||
%% {'subscription_type', 'all'},
|
||||
%% {'subscription_depth', 1}];
|
||||
%%
|
||||
%%default_subscription_options('remote', 'collection') ->
|
||||
%% [{'deliver', true},
|
||||
%% %{'include_body', undefined},
|
||||
%% {'show-values', ['away', 'chat', 'dnd', 'online', 'xa']},
|
||||
%% {'subscription_type', 'all'},
|
||||
%% {'subscription_depth', 1}].
|
||||
|
||||
%%
|
||||
-spec(features/0 :: () -> Features::exmpp_pubsub:features()).
|
||||
|
||||
features() ->
|
||||
[%?NS_ADDRESS,
|
||||
?NS_DISCO_INFO,
|
||||
?NS_DISCO_ITEMS,
|
||||
%?NS_RSM,
|
||||
?NS_VCARD].
|
||||
|
||||
%%
|
||||
identity() ->
|
||||
[{<<"pubsub">>, <<"Publish-Subscribe">>, <<"service">>},
|
||||
{<<"pubsub">>, <<"ejabberd/mod_pubsub/flat">>, <<"service">>}].
|
||||
@@ -0,0 +1,101 @@
|
||||
%% API function definition
|
||||
|
||||
-record(api_core,
|
||||
{
|
||||
create_node = 'pubsub_core' :: module(),
|
||||
delete_node = 'pubsub_core' :: module(),
|
||||
purge_node = 'pubsub_core' :: module(),
|
||||
get_configure_node = 'pubsub_core' :: module(),
|
||||
get_configure_node_default = 'pubsub_core' :: module(),
|
||||
%%
|
||||
publish_item = 'pubsub_core' :: module(),
|
||||
retract_item = 'pubsub_core' :: module(),
|
||||
%%
|
||||
subscribe_node = 'pubsub_core' :: module(),
|
||||
unsubscribe_node = 'pubsub_core' :: module(),
|
||||
set_configure_subscription = 'pubsub_core' :: module(),
|
||||
get_configure_subscription = 'pubsub_core' :: module(),
|
||||
get_configure_subscription_default = 'pubsub_core' :: module(),
|
||||
get_items = 'pubsub_core' :: module(),
|
||||
%%
|
||||
get_entity_affiliations = 'pubsub_core' :: module(),
|
||||
get_entity_subscriptions = 'pubsub_core' :: module(),
|
||||
%%
|
||||
get_node_affiliations = 'pubsub_core' :: module(),
|
||||
get_node_subscriptions = 'pubsub_core' :: module()
|
||||
}).
|
||||
|
||||
-record(api_db,
|
||||
{
|
||||
create_node = 'pubsub_db' :: module(),
|
||||
delete_node = 'pubsub_db' :: module(),
|
||||
purge_node = 'pubsub_db' :: module(),
|
||||
get_configure_node = 'pubsub_db' :: module(),
|
||||
%get_configure_node_default = 'pubsub_db' :: module(),
|
||||
%%
|
||||
publish_item = 'pubsub_db' :: module(),
|
||||
retract_item = 'pubsub_db' :: module(),
|
||||
%%
|
||||
subscribe_node = 'pubsub_db' :: module(),
|
||||
unsubscribe_node = 'pubsub_db' :: module(),
|
||||
set_configure_subscription = 'pubsub_db' :: module(),
|
||||
get_configure_subscription = 'pubsub_db' :: module(),
|
||||
get_configure_subscription_default = 'pubsub_db' :: module(),
|
||||
get_items = 'pubsub_db' :: module(),
|
||||
%%
|
||||
get_entity_affiliations = 'pubsub_db' :: module(),
|
||||
get_entity_subscriptions = 'pubsub_db' :: module(),
|
||||
%%
|
||||
get_node_affiliations = 'pubsub_db' :: module(),
|
||||
get_node_subscriptions = 'pubsub_db' :: module()
|
||||
}).
|
||||
|
||||
-record(api_broadcast,
|
||||
{
|
||||
broadcast_publish = 'pubsub_broadcast' :: module(),
|
||||
broadcast_publish_last = 'pubsub_broadcast' :: module(),
|
||||
notify_create = 'pubsub_broadcast' :: module(),
|
||||
notify_delete = 'pubsub_broadcast' :: module(),
|
||||
notify_publish = 'pubsub_broadcast' :: module(),
|
||||
notify_purge = 'pubsub_broadcast' :: module(),
|
||||
notify_retract = 'pubsub_broadcast' :: module(),
|
||||
notify_subscription = 'pubsub_broadcast' :: module(),
|
||||
notify_subscriptions = 'pubsub_broadcast' :: module()
|
||||
}).
|
||||
|
||||
-record(api,
|
||||
{
|
||||
core = #api_core{} :: #api_core{},
|
||||
db = #api_db{} :: #api_db{},
|
||||
broadcast = #api_broadcast{} :: #api_broadcast{},
|
||||
parser = 'pubsub_parser' :: module(),
|
||||
options = 'pubsub_options' :: module()
|
||||
}).
|
||||
|
||||
-record(capabilities,
|
||||
{
|
||||
plugin :: exmpp_pubsub:plugin(),
|
||||
privacy = false :: boolean(),
|
||||
api = #api{} :: #api{}
|
||||
}).
|
||||
|
||||
-record(api2,
|
||||
{
|
||||
func,
|
||||
core :: 'core',
|
||||
db :: 'db',
|
||||
bkd :: 'mnesia',
|
||||
rtr :: 'router'
|
||||
}).
|
||||
|
||||
-record(mod_pubsub,
|
||||
{
|
||||
server,
|
||||
component,
|
||||
plugin,
|
||||
entity,
|
||||
parameters,
|
||||
features,
|
||||
parser,
|
||||
options
|
||||
}).
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,147 @@
|
||||
|
||||
|
||||
%-include_lib("exmpp/include/exmpp.hrl").
|
||||
%-include_lib("exmpp/include/exmpp_jid.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("ejabberd.hrl").
|
||||
-include("mod_roster.hrl").
|
||||
-include("jlib.hrl").
|
||||
%-include("pubsub_api.hrl").
|
||||
|
||||
-define(NS_JABBER_CLIENT, <<"jabber:client">>).
|
||||
|
||||
%%
|
||||
%% Pubsub Node
|
||||
-record(pubsub_node_dev,
|
||||
{
|
||||
id ,%:: {Pubsub_Host :: exmpp_pubsub:host(),
|
||||
% NodeId :: undefined | exmpp_pubsub:nodeId()},
|
||||
idx ,%:: exmpp_pubsub:nodeIdx(),
|
||||
creation ,%:: {DateTime::erlang:timestamp(), Entity::xmpp_jid:usr_entity()},
|
||||
level = 0 ,%:: exmpp_pubsub:level(),
|
||||
owners = [] ,%:: [Owner::xmpp_jid:usr_bare(),...],
|
||||
itemids = [] ,%:: [ItemId::exmpp_pubsub:itemId()],
|
||||
options = [] %:: pubsub_options:options_node()
|
||||
}).
|
||||
|
||||
%%
|
||||
%% Pubsub State
|
||||
-record(pubsub_state_dev,
|
||||
{
|
||||
id ,%:: {Entity :: xmpp_jid:usr_bare(),
|
||||
% NodeIdx :: exmpp_pubsub:nodeIdx()},
|
||||
nodeidx ,%:: exmpp_pubsub:nodeIdx(),
|
||||
affiliation = 'none' ,%:: exmpp_pubsub:affiliation(),
|
||||
access ,%:: pubsub_options:access_model(),
|
||||
subscriptions = [] ,%:: [] | exmpp_pubsub:subscriptions(),
|
||||
%groups = [] ,%:: [Roster_Group::binary()],
|
||||
itemids = [] %:: [ItemId::exmpp_pubsub:itemId()]
|
||||
}).
|
||||
|
||||
%%
|
||||
%% Pubsub Item
|
||||
-record(pubsub_item_dev,
|
||||
{
|
||||
id ,%:: {ItemId::exmpp_pubsub:itemId(), NodeIdx::exmpp_pubsub:nodeIdx()},
|
||||
nodeidx ,%:: exmpp_pubsub:nodeIdx(),
|
||||
owners = [] ,%:: [Owner::xmpp_jid:usr_bare(),...],
|
||||
creation ,%:: {DateTime::erlang:timestamp(), Entity::xmpp_jid:usr_entity()},
|
||||
modification ,%:: {DateTime::erlang:timestamp(), Entity::xmpp_jid:usr_entity()},
|
||||
payload ,%:: exmpp_pubsub:payload(),
|
||||
options = [] %:: [] | pubsub_options:options_item()
|
||||
}).
|
||||
|
||||
%%
|
||||
%% Pubsub Last Item
|
||||
-record(pubsub_last_item_dev,
|
||||
{
|
||||
nodeidx ,%:: exmpp_pubsub:nodeIdx(),
|
||||
id ,%:: exmpp_pubsub:itemId(),
|
||||
owners = [] ,%:: [Owner::xmpp_jid:usr_bare(),...],
|
||||
creation ,%:: {DateTime::erlang:timestamp(), Entity::xmpp_jid:usr_entity()},
|
||||
payload ,%:: exmpp_pubsub:payload(),
|
||||
options = [] %:: [] | pubsub_options:options_item()
|
||||
}).
|
||||
|
||||
%%
|
||||
%% Pubsub Index
|
||||
-record(pubsub_index_dev,
|
||||
{
|
||||
index :: exmpp_pubsub:index(),
|
||||
last :: exmpp_pubsub:nodeIdx(),
|
||||
free :: [exmpp_pubsub:nodeIdx()]
|
||||
}).
|
||||
|
||||
%%
|
||||
%% Pubsub_Subscription_Pending
|
||||
-record(pubsub_subscription_pending,
|
||||
{
|
||||
id ,%:: {Entity::xmpp_jid:usr_bare(), NodeIdx::exmpp_pubsub:nodeIdx()}
|
||||
nodeidx ,%:: exmpp_pubsub:nodeIdx()
|
||||
subids %:: [SubId::exmpp_pubsub:subId(),...]
|
||||
}).
|
||||
|
||||
|
||||
|
||||
%%
|
||||
%% Internal data structures
|
||||
%%
|
||||
-record(entity,
|
||||
{
|
||||
id :: xmpp_jid:usr_bare(),
|
||||
local :: boolean(),
|
||||
affiliation :: 'member' | 'owner' | 'publisher',
|
||||
subscriptions :: []%[exmpp_pubsub:subscription(),...]
|
||||
}).
|
||||
|
||||
%%
|
||||
-record(node,
|
||||
{
|
||||
id :: exmpp_pubsub:nodeId(),
|
||||
owners :: [Node_Owner::xmpp_jid:usr_bare(),...],
|
||||
access_model :: pubsub_options:access_model(),
|
||||
% itemreply :: 'owner' | 'publisher',
|
||||
% notification_type :: 'headline' | 'normal',
|
||||
% presence_based_delivery :: boolean(),
|
||||
rosters_groups_allowed = [] :: [] | pubsub_options:rosters_groups_allowed()
|
||||
}).
|
||||
|
||||
%%
|
||||
-record(item,
|
||||
{
|
||||
access_model ,%:: undefined | pubsub_options:access_model(),
|
||||
presence_based_delivery ,%:: undefined | boolean(),
|
||||
rosters_groups_allowed = [],%:: [] | pubsub_options:rosters_groups_allowed()
|
||||
stanza %::#xmlel{}
|
||||
}).
|
||||
|
||||
%%
|
||||
-record(cache,
|
||||
{
|
||||
%% Entity is online
|
||||
presence :: undefined | mod_pubsub_dev:presence_cache(),
|
||||
%% Entity has presence subscriptions with at least one node owner
|
||||
presence_subscriptions :: undefined | boolean(),
|
||||
%% Entity has presence subscriptions with at least one node owner
|
||||
%% and is contained in at least one roster group from the node owner
|
||||
rosters_groups :: undefined | boolean() %% TODO : use a list
|
||||
}).
|
||||
|
||||
%%
|
||||
-record(subids,
|
||||
{
|
||||
presence = undefined :: undefined | [] | mod_pubsub_dev:resources_subids(),
|
||||
no_presence = undefined :: undefined | [] | mod_pubsub_dev:resources_subids()
|
||||
}).
|
||||
|
||||
%%
|
||||
-record(event,
|
||||
{
|
||||
host :: xmpp_jid:raw_jid_component_bare(),
|
||||
component :: xmpp_jid:component_bare(),
|
||||
entity :: mod_pubsub_dev:entity(),
|
||||
node :: mod_pubsub_dev:n0de(),
|
||||
cache :: mod_pubsub_dev:cache(),
|
||||
subids :: mod_pubsub_dev:subids()
|
||||
}).
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,904 @@
|
||||
%%% ====================================================================
|
||||
%%% ``The contents of this file are subject to the Erlang Public License,
|
||||
%%% Version 1.1, (the "License"); you may not use this file except in
|
||||
%%% compliance with the License. You should have received a copy of the
|
||||
%%% Erlang Public License along with this software. If not, it can be
|
||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||
%%%
|
||||
%%% Software distributed under the License is distributed on an "AS IS"
|
||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
%%% the License for the specific language governing rights and limitations
|
||||
%%% under the License.
|
||||
%%%
|
||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
||||
%%% Portions created by ProcessOne are Copyright 2006-2013, ProcessOne
|
||||
%%% All Rights Reserved.''
|
||||
%%% This software is copyright 2006-2013, ProcessOne.
|
||||
%%%
|
||||
%%% @copyright 2006-2013 ProcessOne
|
||||
%%% @author Karim Gemayel <karim.gemayel@process-one.net>
|
||||
%%% [http://www.process-one.net/]
|
||||
%%% @version {@vsn}, {@date} {@time}
|
||||
%%% @end
|
||||
%%% ====================================================================
|
||||
|
||||
%%% @headerfile "pubsub_dev.hrl"
|
||||
|
||||
-module(pubsub_groups).
|
||||
-author('karim.gemayel@process-one.net').
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
-include("pubsub_dev.hrl").
|
||||
|
||||
-import(pubsub_tools,
|
||||
[
|
||||
get_option/2,
|
||||
get_option/3,
|
||||
get_value/2,
|
||||
get_value/3,
|
||||
set_value/3,
|
||||
%%
|
||||
check_acces_model/3,
|
||||
check_acces_model/7,
|
||||
check_publish_model/3,
|
||||
get_entity_roster/1,
|
||||
is_contact_subscribed_to_node_owners/3,
|
||||
is_contact_in_allowed_roster_groups/2,
|
||||
has_subscriptions/1,
|
||||
get_resources/2,
|
||||
get_resources_show/2,
|
||||
rosters_groups_allowed_cache/2
|
||||
]).
|
||||
|
||||
-import(pubsub_db_mnesia,
|
||||
[
|
||||
table/2
|
||||
]).
|
||||
|
||||
|
||||
-type(group() :: binary()).
|
||||
|
||||
-type(node_group() :: group()).
|
||||
|
||||
-type(roster_group() :: group()).
|
||||
|
||||
-type(node_groups() :: [Node_Group::node_group(),...]).
|
||||
|
||||
-type(roster_groups() :: [Roster_Group::roster_group(),...]).
|
||||
|
||||
-type(nodeIdxs() :: [NodeIdx::exmpp_pubsub:nodeIdx(),...]).
|
||||
|
||||
-type(n0de()
|
||||
:: {NodeIdx :: exmpp_pubsub:nodeIdx(),
|
||||
Groups :: node_groups()}
|
||||
).
|
||||
|
||||
-type(n0des() :: [Node::n0de(),...]).
|
||||
|
||||
%% -type(subscription()
|
||||
%% :: {NodeIdx :: exmpp_pubsub:nodeIdx(),
|
||||
%% Groups :: roster_groups()}
|
||||
%% ).
|
||||
|
||||
-type(subscriptions() :: [Subscription::subscription(),...]).
|
||||
|
||||
-type(contact()
|
||||
:: {Entity :: xmpp_jid:usr_bare(),
|
||||
Subscriptions :: subscriptions()}
|
||||
).
|
||||
|
||||
-type(contacts() :: [Contact::contact(),...]).
|
||||
|
||||
|
||||
-record(pubsub_groups,
|
||||
{
|
||||
owner :: xmpp_jid:usr_bare(),
|
||||
nodes = [] :: n0des(),
|
||||
contacts = [] :: [] | contacts()
|
||||
}).
|
||||
|
||||
|
||||
create_table_pubsub_groups(Suffix) ->
|
||||
mnesia:create_table(table('pubsub_groups', Suffix),
|
||||
[{type, set},
|
||||
{disc_copies, [node()]},
|
||||
{record_name, pubsub_groups},
|
||||
{attributes, record_info(fields, pubsub_groups)}]).
|
||||
|
||||
|
||||
|
||||
%%
|
||||
-spec(register_groups/4 ::
|
||||
(
|
||||
Suffix :: atom(),
|
||||
NodeIdx :: exmpp_pubsub:nodeIdx(),
|
||||
Owner :: xmpp_jid:usr_bare(),
|
||||
Groups :: [] | node_groups())
|
||||
-> undefined
|
||||
%
|
||||
| {Subscribers :: [Entity::xmpp_jid:usr_bare()],
|
||||
Unsubscribers :: [Entity::xmpp_jid:usr_bare()]}
|
||||
).
|
||||
|
||||
register_groups(Suffix, NodeIdx, Owner, [] = _Groups) ->
|
||||
case
|
||||
mnesia:read(Table_Pubsub_Groups = table('pubsub_groups', 'dev'),
|
||||
Owner, write)
|
||||
of
|
||||
%%
|
||||
[] ->
|
||||
undefined;
|
||||
%%
|
||||
[#pubsub_groups{nodes = [{NodeIdx, _Node_Groups}]} = Pubsub_Groups] ->
|
||||
mnesia:delete_object(Table_Pubsub_Groups, Pubsub_Groups, write),
|
||||
%
|
||||
{_Subscribers = [],
|
||||
_Unsubscribers = lists:foldl(fun
|
||||
({Entity, Subscriptions}, Unsubscribers) ->
|
||||
case lists:keymember(NodeIdx, 1, Subscriptions) of
|
||||
true -> [Entity | Unsubscribers];
|
||||
false -> Unsubscribers
|
||||
end
|
||||
%
|
||||
end, [], Pubsub_Groups#pubsub_groups.contacts)};
|
||||
%%
|
||||
[Pubsub_Groups] ->
|
||||
case lists:keyfind(NodeIdx, 1, Pubsub_Groups#pubsub_groups.nodes) of
|
||||
{_NodeIdx, Node_Groups} ->
|
||||
{Contacts, Unsubscribers} = subscriptions1(NodeIdx,
|
||||
Pubsub_Groups#pubsub_groups.contacts),
|
||||
%
|
||||
mnesia:write(Table_Pubsub_Groups,
|
||||
Pubsub_Groups#pubsub_groups{
|
||||
contacts = Contacts
|
||||
},
|
||||
write),
|
||||
%
|
||||
{_Subscribers = [],
|
||||
_Unsubscribers = Unsubscribers};
|
||||
false ->
|
||||
undefined
|
||||
end
|
||||
end;
|
||||
%%
|
||||
register_groups(Suffix, NodeIdx, Owner, Groups) ->
|
||||
case
|
||||
mnesia:read(Table_Pubsub_Groups = table('pubsub_groups', 'dev'), Owner,
|
||||
write)
|
||||
of
|
||||
[] ->
|
||||
{Contacts, Subscribers} = subscriptions2(NodeIdx, Owner, Groups),
|
||||
%
|
||||
mnesia:write(Table_Pubsub_Groups,
|
||||
#pubsub_groups{
|
||||
owner = Owner,
|
||||
nodes = [{NodeIdx, Groups}],
|
||||
contacts = Contacts
|
||||
},
|
||||
write),
|
||||
%
|
||||
{_Subscribers = Subscribers,
|
||||
_Unsubscribers = []};
|
||||
[Pubsub_Groups] ->
|
||||
case lists:keyfind(NodeIdx, 1, Pubsub_Groups#pubsub_groups.nodes) of
|
||||
{_NodeIdx, Node_Groups} ->
|
||||
case diff_groups(Groups, Node_Groups) of
|
||||
%%
|
||||
{[] = _New_Groups, [] = _Old_Groups} ->
|
||||
{_Subscribers = [],
|
||||
_Unsubscribers = []};
|
||||
%%
|
||||
{[] = _New_Groups, Old_Groups} ->
|
||||
{Contacts, Unsubscribers}
|
||||
= subscriptions3(NodeIdx, Old_Groups,
|
||||
Pubsub_Groups#pubsub_groups.contacts),
|
||||
%
|
||||
mnesia:write(Table_Pubsub_Groups,
|
||||
Pubsub_Groups#pubsub_groups{
|
||||
nodes = lists:keyreplace(NodeIdx, 1,
|
||||
Pubsub_Groups#pubsub_groups.nodes,
|
||||
{NodeIdx, Groups}),
|
||||
contacts = Contacts
|
||||
},
|
||||
write),
|
||||
%
|
||||
{_Subscribers = [],
|
||||
_Unsubscribers = Unsubscribers};
|
||||
%%
|
||||
{_New_Groups, _Old_Groups} ->
|
||||
{Contacts, Subscribers, Unsubscribers}
|
||||
= subscriptions4(NodeIdx, Owner, Node_Groups,
|
||||
Pubsub_Groups#pubsub_groups.contacts),
|
||||
%
|
||||
mnesia:write(Table_Pubsub_Groups,
|
||||
Pubsub_Groups#pubsub_groups{
|
||||
nodes = lists:keyreplace(NodeIdx, 1,
|
||||
Pubsub_Groups#pubsub_groups.nodes,
|
||||
{NodeIdx, Node_Groups}),
|
||||
contacts = Contacts
|
||||
},
|
||||
write),
|
||||
%
|
||||
{Subscribers = Subscribers,
|
||||
_Unsubscribers = Unsubscribers}
|
||||
end;
|
||||
false ->
|
||||
{Contacts, Subscribers}
|
||||
= subscriptions5(NodeIdx, Owner, Groups,
|
||||
_Contacts = Pubsub_Groups#pubsub_groups.contacts),
|
||||
%
|
||||
mnesia:write(Table_Pubsub_Groups,
|
||||
Pubsub_Groups#pubsub_groups{
|
||||
nodes = [{NodeIdx, Groups}
|
||||
| Pubsub_Groups#pubsub_groups.nodes],
|
||||
contacts = Contacts
|
||||
},
|
||||
write),
|
||||
%
|
||||
{_Subscribers = Subscribers,
|
||||
_Unsubscribers = []}
|
||||
end
|
||||
end.
|
||||
|
||||
|
||||
%% TODO : fix this hook managment
|
||||
-spec(monitor_contacts/3 ::
|
||||
(
|
||||
_ :: 'subscribed',
|
||||
Entity :: xmpp_jid:usr_bare(),
|
||||
Jid_Contacts :: xmpp_jid:entity_bare())
|
||||
-> undefined
|
||||
%
|
||||
| {Server :: xmpp_jid:raw_jid_component_bare(),
|
||||
Entity :: xmpp_jid:usr_bare(),
|
||||
Contact :: xmpp_jid:usr_bare(),
|
||||
_ :: {'subscribed', NodeIdxs :: nodeIdxs()}}
|
||||
).
|
||||
|
||||
monitor_contacts('subscribed', {_, Server, _} = Entity, Jid_Contact) ->
|
||||
case roster_groups(Entity, Contact = jlid:jid_to_lower(Jid_Contact)) of
|
||||
[] ->
|
||||
undefined;
|
||||
Roster_Groups ->
|
||||
case
|
||||
mnesia:read(Table_Pubsub_Groups = table('pubsub_groups', dev),
|
||||
_Owner = Entity, write)
|
||||
of
|
||||
[] ->
|
||||
undefined;
|
||||
[Pubsub_Groups] ->
|
||||
case
|
||||
filter_subscriptions(Pubsub_Groups#pubsub_groups.nodes,
|
||||
Roster_Groups)
|
||||
of
|
||||
[] ->
|
||||
undefined;
|
||||
Subscriptions ->
|
||||
mnesia:write(Table_Pubsub_Groups,
|
||||
Pubsub_Groups#pubsub_groups{
|
||||
contacts = case
|
||||
lists:keyreplace(Contact, 1,
|
||||
Pubsub_Groups#pubsub_groups.contacts,
|
||||
{Contact, Subscriptions})
|
||||
of
|
||||
_Contacts
|
||||
when _Contacts ==
|
||||
Pubsub_Groups#pubsub_groups.contacts ->
|
||||
[{Contact, Subscriptions}
|
||||
| Pubsub_Groups#pubsub_groups.contacts];
|
||||
Contacts ->
|
||||
Contacts
|
||||
end
|
||||
},
|
||||
write),
|
||||
{Server, Entity, Contact,
|
||||
{'subscribed',
|
||||
_NodeIdx = lists:map(fun
|
||||
({NodeIdx, _Groups}) ->
|
||||
NodeIdx
|
||||
end, Subscriptions)}}
|
||||
end
|
||||
end
|
||||
end.
|
||||
|
||||
|
||||
%%
|
||||
-spec(monitor_groups/2 ::
|
||||
(
|
||||
Server :: xmpp_jid:raw_jid_component_bare(),
|
||||
Roster :: #roster{groups :: [] | roster_groups()})
|
||||
-> undefined
|
||||
%
|
||||
| {Server :: xmpp_jid:raw_jid_component_bare(),
|
||||
Entity :: xmpp_jid:usr_bare(),
|
||||
Diff_NodeIdxs :: {NodeIdxs_Subscriptions :: [] | nodeIdxs(),
|
||||
NodeIdxs_Unsubscriptions :: [] | nodeIdxs()}}
|
||||
).
|
||||
|
||||
monitor_groups(Server, #roster{us = {U,S}} = _Roster) ->
|
||||
case
|
||||
mnesia:read(Table_Pubsub_Groups = table('pubsub_groups', dev),
|
||||
_Owner = {U,S,undefined}, write)
|
||||
of
|
||||
[] ->
|
||||
undefined;
|
||||
[Pubsub_Groups] ->
|
||||
case
|
||||
lists:keyfind(_Roster#roster.jid, 1,
|
||||
Pubsub_Groups#pubsub_groups.contacts)
|
||||
of %%
|
||||
{_Entity, Old_Subscriptions}
|
||||
when _Roster#roster.subscription == 'delete'
|
||||
orelse _Roster#roster.subscription == 'none' ->
|
||||
mnesia:write(Table_Pubsub_Groups,
|
||||
Pubsub_Groups#pubsub_groups{
|
||||
contacts = lists:keydelete(_Roster#roster.jid, 1,
|
||||
Pubsub_Groups#pubsub_groups.contacts)
|
||||
},
|
||||
write),
|
||||
{Server,
|
||||
_Entity = _Roster#roster.jid,
|
||||
_Diff_NodeIdxs = diff_nodeidxs(_New_Subscriptions = [],
|
||||
Old_Subscriptions)};
|
||||
%%
|
||||
{_Entity, Old_Subscriptions}
|
||||
when (_Roster#roster.subscription == 'both'
|
||||
orelse
|
||||
_Roster#roster.subscription == 'from')
|
||||
andalso _Roster#roster.groups == [] ->
|
||||
mnesia:write(Table_Pubsub_Groups,
|
||||
Pubsub_Groups#pubsub_groups{
|
||||
contacts = lists:keydelete(_Roster#roster.jid, 1,
|
||||
Pubsub_Groups#pubsub_groups.contacts)
|
||||
},
|
||||
write),
|
||||
{Server,
|
||||
_Roster#roster.jid,
|
||||
_Diff_NodeIdxs = diff_nodeidxs(_New_Subscriptions = [],
|
||||
Old_Subscriptions)};
|
||||
%%
|
||||
{_Entity, Old_Subscriptions}
|
||||
when _Roster#roster.subscription == 'both'
|
||||
orelse _Roster#roster.subscription == 'from' ->
|
||||
case
|
||||
filter_subscriptions(Pubsub_Groups#pubsub_groups.nodes,
|
||||
_Roster#roster.groups)
|
||||
of
|
||||
[] ->
|
||||
mnesia:write(Table_Pubsub_Groups,
|
||||
Pubsub_Groups#pubsub_groups{
|
||||
contacts = lists:keydelete(_Roster#roster.jid,
|
||||
1, Pubsub_Groups#pubsub_groups.contacts)
|
||||
},
|
||||
write),
|
||||
{Server, _Roster#roster.jid,
|
||||
diff_nodeidxs(_New_Subscriptions = [],
|
||||
Old_Subscriptions)};
|
||||
New_Subscriptions ->
|
||||
mnesia:write(Table_Pubsub_Groups,
|
||||
Pubsub_Groups#pubsub_groups{
|
||||
contacts = lists:keyreplace(_Roster#roster.jid,
|
||||
1, Pubsub_Groups#pubsub_groups.contacts,
|
||||
{_Roster#roster.jid, New_Subscriptions})
|
||||
},
|
||||
write),
|
||||
{Server,
|
||||
_Entity = _Roster#roster.jid,
|
||||
_Diff_NodeIdxs = diff_nodeidxs(New_Subscriptions,
|
||||
Old_Subscriptions)}
|
||||
end;
|
||||
%%
|
||||
false
|
||||
when (_Roster#roster.subscription == 'both'
|
||||
orelse
|
||||
_Roster#roster.subscription == 'from')
|
||||
andalso _Roster#roster.groups =/= [] ->
|
||||
case
|
||||
filter_subscriptions(Pubsub_Groups#pubsub_groups.nodes,
|
||||
_Roster#roster.groups)
|
||||
of
|
||||
[] ->
|
||||
undefined;
|
||||
New_Subscriptions ->
|
||||
mnesia:write(Table_Pubsub_Groups,
|
||||
Pubsub_Groups#pubsub_groups{
|
||||
contacts = [{_Roster#roster.jid, New_Subscriptions}
|
||||
| Pubsub_Groups#pubsub_groups.contacts]
|
||||
},
|
||||
write),
|
||||
{Server,
|
||||
_Entity = _Roster#roster.jid,
|
||||
_Diff_NodeIdxs = diff_nodeidxs(New_Subscriptions,
|
||||
_Old_Subscriptions = [])}
|
||||
end;
|
||||
%%
|
||||
_ ->
|
||||
undefined
|
||||
end
|
||||
end.
|
||||
|
||||
|
||||
|
||||
%%
|
||||
%%
|
||||
-spec(subscriptions1/2 ::
|
||||
(
|
||||
NodeIdx :: exmpp_pubsub:nodeIdx(),
|
||||
Old_Contacts :: [] | contacts())
|
||||
-> Diff_Contacts :: {New_Contacts :: [] | contacts(),
|
||||
Unsubscribers :: [Entity::xmpp_jid:usr_bare()]}
|
||||
).
|
||||
|
||||
subscriptions1(NodeIdx, Contacts) ->
|
||||
_Diff_Contacts = subscriptions1(NodeIdx, _Old_Contacts = Contacts,
|
||||
{_New_Contacts = [], _Unsubscribers = []}).
|
||||
|
||||
|
||||
%%
|
||||
-spec(subscriptions1/3 ::
|
||||
(
|
||||
NodeIdx :: exmpp_pubsub:nodeIdx(),
|
||||
Old_Contacts :: [] | contacts(),
|
||||
Diff_Contacts :: {Contacts :: [] | contacts(),
|
||||
Unsubscribers :: [Entity::xmpp_jid:usr_bare()]})
|
||||
-> Diff_Contacts :: {New_Contacts :: [] | contacts(),
|
||||
Unsubscribers :: [Entity::xmpp_jid:usr_bare()]}
|
||||
).
|
||||
|
||||
subscriptions1(_NodeIdx, [] = _Old_Contacts, Diff_Contacts) ->
|
||||
Diff_Contacts;
|
||||
%%
|
||||
subscriptions1(NodeIdx, [{Entity, Subscriptions} | Old_Contacts],
|
||||
{Contacts, Unsubscribers}) ->
|
||||
subscriptions1(NodeIdx, Old_Contacts,
|
||||
_Diff_Contacts = case lists:keydelete(NodeIdx, 1, Subscriptions) of
|
||||
[] ->
|
||||
{_Contacts = Contacts,
|
||||
_Unsubscribers = [Entity | Unsubscribers]};
|
||||
Subscriptions ->
|
||||
{_Contacts = [{Entity, Subscriptions} | Contacts],
|
||||
_Unsubscribers = Unsubscribers};
|
||||
New_Subscriptions ->
|
||||
{_Contacts = [{Entity, New_Subscriptions} | Contacts],
|
||||
_Unsubscribers = [Entity | Unsubscribers]}
|
||||
end).
|
||||
|
||||
|
||||
%%
|
||||
-spec(subscriptions2/3 ::
|
||||
(
|
||||
NodeIdx :: exmpp_pubsub:nodeIdx(),
|
||||
Owner :: xmpp_jid:usr_bare(),
|
||||
Node_Groups :: node_groups())
|
||||
-> Diff_Contacts :: {Contacts :: [] | contacts(),
|
||||
Subscribers :: [Entity::xmpp_jid:usr_bare()]}
|
||||
).
|
||||
|
||||
subscriptions2(NodeIdx, Owner, Node_Groups) ->
|
||||
subscriptions2(NodeIdx, _Rosters = get_entity_roster(Owner), Node_Groups,
|
||||
{_New_Contacts = [], _Subscribers = []}).
|
||||
|
||||
%%
|
||||
-spec(subscriptions2/4 ::
|
||||
(
|
||||
NodeIdx :: exmpp_pubsub:nodeIdx(),
|
||||
Rosters :: [Roster::#roster{groups :: [] | roster_groups()}],
|
||||
Node_Groups :: node_groups(),
|
||||
Diff_Contacts :: {Contacts :: [] | contacts(),
|
||||
Subscribers :: [Entity::xmpp_jid:usr_bare()]})
|
||||
-> Diff_Contacts :: {Contacts :: [] | contacts(),
|
||||
Subscribers :: [Entity::xmpp_jid:usr_bare()]}
|
||||
).
|
||||
|
||||
subscriptions2(_NodeIdx, [] = _Rosters, _Node_Groups, Diff_Contacts) ->
|
||||
Diff_Contacts;
|
||||
%%
|
||||
subscriptions2(NodeIdx, [_Roster | Rosters], Node_Groups, {Contacts, Subscribers})
|
||||
when _Roster#roster.groups =/= [] ->
|
||||
subscriptions2(NodeIdx, Rosters, Node_Groups,
|
||||
_Diff_Contacts = case
|
||||
filter_groups(_Roster#roster.groups, Node_Groups, [])
|
||||
of
|
||||
[] ->
|
||||
{_Contacts = Contacts,
|
||||
_Subscribers = Subscribers};
|
||||
Roster_Groups ->
|
||||
{_Contacts = [{_Roster#roster.jid, [{NodeIdx, Roster_Groups}]}
|
||||
| Contacts],
|
||||
_Subscribers = [_Roster#roster.jid | Subscribers]}
|
||||
end);
|
||||
%%
|
||||
subscriptions2(NodeIdx, [_Roster | Rosters], Node_Groups, Diff_Contacts) ->
|
||||
subscriptions2(NodeIdx, Rosters, Node_Groups, Diff_Contacts).
|
||||
|
||||
|
||||
%%
|
||||
-spec(subscriptions3/3 ::
|
||||
(
|
||||
NodeIdx :: exmpp_pubsub:nodeIdx(),
|
||||
Old_Groups :: roster_groups(),
|
||||
Contacts :: contacts() | [])
|
||||
-> Diff_Contacts :: {Contacts :: [] | contacts(),
|
||||
Unsubscribers :: [Entity::xmpp_jid:usr_bare()]}
|
||||
).
|
||||
subscriptions3(NodeIdx, Old_Groups, Contacts) ->
|
||||
subscriptions3(NodeIdx, Contacts, Old_Groups, {[],[]}).
|
||||
|
||||
%%
|
||||
-spec(subscriptions3/4 ::
|
||||
(
|
||||
NodeIdx :: exmpp_pubsub:nodeIdx(),
|
||||
Old_Contacts :: contacts() | [],
|
||||
Old_Groups :: roster_groups(),
|
||||
Diff_Contacts :: {Contacts :: [] | contacts(),
|
||||
Unsubscribers :: [Entity::xmpp_jid:usr_bare()]})
|
||||
-> Diff_Contacts :: {Contacts :: [] | contacts(),
|
||||
Unsubscribers :: [Entity::xmpp_jid:usr_bare()]}
|
||||
).
|
||||
|
||||
subscriptions3(_NodeIdx, [] = _Contacts, _Old_Groups, Diff_Contacts) ->
|
||||
Diff_Contacts;
|
||||
%%
|
||||
subscriptions3(NodeIdx, [{Entity, Subscriptions} | Old_Contacts], Old_Groups,
|
||||
{Contacts, Unsubscribers}) ->
|
||||
subscriptions3(NodeIdx, Old_Contacts, Old_Groups,
|
||||
_Diff_Contacts = case lists:keyfind(NodeIdx, 1, Subscriptions) of
|
||||
{_NodeIdx, Roster_Groups} ->
|
||||
case delete_groups(Old_Groups, Roster_Groups) of
|
||||
[] ->
|
||||
{_Contacts = Contacts,
|
||||
_Unsubscribers = [Entity | Unsubscribers]};
|
||||
Groups ->
|
||||
{_Contacts = [{Entity,
|
||||
lists:keyreplace(NodeIdx, 1,
|
||||
Subscriptions, {NodeIdx, Groups})}
|
||||
| Contacts],
|
||||
_Unsubscribers = Unsubscribers}
|
||||
end;
|
||||
false ->
|
||||
{_Contacts = [{Entity, Subscriptions} | Contacts],
|
||||
_Unsubscribers = Unsubscribers}
|
||||
end).
|
||||
|
||||
|
||||
%%
|
||||
-spec(subscriptions4/4 ::
|
||||
(
|
||||
NodeIdx :: exmpp_pubsub:nodeIdx(),
|
||||
_ :: xmpp_jid:usr_bare()
|
||||
| [Roster::#roster{groups :: [] | roster_groups()}],
|
||||
Node_Groups :: node_groups(),
|
||||
_ :: [] | contacts()
|
||||
| {Contacts :: [] | contacts(),
|
||||
Subscribers :: [Entity::xmpp_jid:usr_bare()],
|
||||
Unsubscribers :: [Entity::xmpp_jid:usr_bare()]})
|
||||
-> Diff_Contacts :: {Contacts :: [] | contacts(),
|
||||
Subscribers :: [Entity::xmpp_jid:usr_bare()],
|
||||
Unsubscribers :: [Entity::xmpp_jid:usr_bare()]}
|
||||
).
|
||||
|
||||
subscriptions4(_NodeIdx, [] = _Rosters, _Node_Groups, Diff_Contacts) ->
|
||||
Diff_Contacts;
|
||||
%%
|
||||
subscriptions4(NodeIdx, [_Roster | Rosters], Node_Groups,
|
||||
{Contacts, Subscribers, Unsubscribers})
|
||||
when _Roster#roster.groups =/= [] ->
|
||||
subscriptions4(NodeIdx, Rosters, Node_Groups,
|
||||
_Diff_Contacts = case
|
||||
{lists:keyfind(Entity = _Roster#roster.jid, 1, Contacts),
|
||||
filter_groups(_Roster#roster.groups, Node_Groups, [])}
|
||||
of
|
||||
%%
|
||||
{false, [] = _Groups} ->
|
||||
{_Contacts = Contacts,
|
||||
_Subscribers = Subscribers,
|
||||
_Unsubscribers = Unsubscribers};
|
||||
%%
|
||||
{false, Groups} ->
|
||||
{_Contacts = [{Entity, [{NodeIdx, Groups}]} | Contacts],
|
||||
_Subscribers = [Entity | Subscribers],
|
||||
_Unsubscribers = Unsubscribers};
|
||||
%%
|
||||
{{_Entity, [{NodeIdx, _Roster_Groups}] = _Subscriptions}, [] = _Groups} ->
|
||||
{_Contacts = lists:keydelete(Entity, 1, Contacts),
|
||||
_Subscribers = Subscribers,
|
||||
_Unsubscribers = [Entity | Unsubscribers]};
|
||||
%%
|
||||
{{_Entity, Subscriptions}, [] = _Groups} ->
|
||||
case lists:keydelete(NodeIdx, 1, Subscriptions) of
|
||||
Subscriptions ->
|
||||
{_Contacts = Contacts,
|
||||
_Subscribers = Subscribers,
|
||||
_Unsubscribers = Unsubscribers};
|
||||
New_Subscriptions ->
|
||||
{_Contacts = lists:keyreplace(Entity, 1, Contacts,
|
||||
{Entity, New_Subscriptions}),
|
||||
_Subscribers = Subscribers,
|
||||
_Unsubscribers = [Entity | Unsubscribers]}
|
||||
end;
|
||||
{{_Entity, Subscriptions}, Groups} ->
|
||||
case lists:keyreplace(NodeIdx, 1, Subscriptions, {NodeIdx, Groups}) of
|
||||
Subscriptions ->
|
||||
{_Contacts = lists:keyreplace(Entity, 1, Contacts,
|
||||
{Entity,
|
||||
[{NodeIdx, Groups} | Subscriptions]}),
|
||||
_Subscribers = [Entity | Subscribers],
|
||||
_Unsubscribers = Unsubscribers};
|
||||
New_Subscriptions ->
|
||||
{_Contacts = lists:keyreplace(Entity, 1, Contacts,
|
||||
{Entity, New_Subscriptions}),
|
||||
_Subscribers = Subscribers,
|
||||
_Unsubscribers = Unsubscribers}
|
||||
end
|
||||
end);
|
||||
%%
|
||||
subscriptions4(NodeIdx, [_Roster | Rosters], Node_Groups, Diff_Contacts) ->
|
||||
subscriptions4(NodeIdx, Rosters, Node_Groups, Diff_Contacts);
|
||||
%%
|
||||
subscriptions4(NodeIdx, Owner, Node_Groups, Contacts) ->
|
||||
subscriptions4(NodeIdx, _Rosters = get_entity_roster(Owner), Node_Groups,
|
||||
_Diff_Contacts = {Contacts, _Subscribers = [], _Unsubscribers = []}).
|
||||
|
||||
|
||||
|
||||
-spec(subscriptions5/4 ::
|
||||
(
|
||||
NodeIdx :: exmpp_pubsub:nodeIdx(),
|
||||
_ :: xmpp_jid:usr_bare()
|
||||
| [Roster::#roster{groups :: [] | roster_groups()}],
|
||||
Node_Groups :: node_groups(),
|
||||
_ :: [] | contacts()
|
||||
| {Contacts :: [] | contacts(),
|
||||
Subscribers :: [Entity::xmpp_jid:usr_bare()]})
|
||||
-> Diff_Contacts :: {Contacts :: [] | contacts(),
|
||||
Subscribers :: [Entity::xmpp_jid:usr_bare()]}
|
||||
).
|
||||
|
||||
subscriptions5(NodeIdx, [_Roster | Rosters], Node_Groups, {Contacts, Subscribers})
|
||||
when _Roster#roster.groups =/= [] ->
|
||||
subscriptions5(NodeIdx, Rosters, Node_Groups,
|
||||
_Diff_Contacts = case
|
||||
filter_groups(_Roster#roster.groups, Node_Groups, [])
|
||||
of
|
||||
[] ->
|
||||
{_Contacts = Contacts,
|
||||
_Subscribers = Subscribers};
|
||||
Groups ->
|
||||
{_Contacts = case
|
||||
lists:keyfind(_Roster#roster.jid, 1, Contacts)
|
||||
of
|
||||
false ->
|
||||
[{_Roster#roster.jid, [{NodeIdx, Groups}]} | Contacts];
|
||||
{Entity, Subscriptions} ->
|
||||
lists:keyreplace(Entity, 1, Contacts,
|
||||
{Entity, [{NodeIdx, Groups} | Subscriptions]})
|
||||
end,
|
||||
_Subscribers = [_Roster#roster.jid | Subscribers]}
|
||||
end);
|
||||
%%
|
||||
subscriptions5(NodeIdx, [_Roster | Rosters], Node_Groups, Diff_Contacts) ->
|
||||
subscriptions5(NodeIdx, Rosters, Node_Groups, Diff_Contacts);
|
||||
%%
|
||||
subscriptions5(NodeIdx, Owner, Node_Groups, Contacts) ->
|
||||
subscriptions5(NodeIdx, _Rosters = get_entity_roster(Owner), Node_Groups,
|
||||
_Diff_Contacts = {Contacts, _Subscribers = []}).
|
||||
|
||||
|
||||
%%
|
||||
-spec(delete_groups/2 ::
|
||||
(
|
||||
Old_Groups :: roster_groups(),
|
||||
Groups :: [] | roster_groups())
|
||||
-> Groups :: [] | roster_groups()
|
||||
).
|
||||
|
||||
delete_groups(_Old_Groups, [] = _Groups) ->
|
||||
_Groups = [];
|
||||
%%
|
||||
delete_groups([] = _Old_Groups, Groups) ->
|
||||
Groups;
|
||||
%%
|
||||
delete_groups([Old_Group | Old_Groups], Groups) ->
|
||||
_Groups = delete_groups(Old_Groups, lists:delete(Old_Group, Groups)).
|
||||
|
||||
|
||||
%%
|
||||
-spec(diff_groups/2 ::
|
||||
(
|
||||
Groups :: node_groups() | [],
|
||||
_ :: node_groups()
|
||||
| {New_Groups :: [] | node_groups(),
|
||||
Old_Groups :: [] | node_groups()})
|
||||
-> Diff_Groups :: {New_Groups :: [] | node_groups(),
|
||||
Old_Groups :: [] | node_groups()}
|
||||
).
|
||||
|
||||
diff_groups([] = _Groups, Diff_Groups) -> %% when is_tuple(Diff_Groups)
|
||||
Diff_Groups;
|
||||
%%
|
||||
diff_groups([Group | Groups], {New_Groups, Old_Groups}) ->
|
||||
diff_groups(Groups,
|
||||
_Diff_Groups = case lists:delete(Group, Old_Groups) of
|
||||
Old_Groups -> {[Group | New_Groups], Old_Groups};
|
||||
Old_Groups2 -> {New_Groups, Old_Groups2}
|
||||
end);
|
||||
%%
|
||||
diff_groups(New_Groups, Old_Groups) ->
|
||||
diff_groups(New_Groups, {[], Old_Groups}).
|
||||
|
||||
|
||||
%%
|
||||
-spec(filter_groups/3 ::
|
||||
(
|
||||
Roster_Groups :: roster_groups() | [],
|
||||
Node_Groups :: node_groups(),
|
||||
Groups :: [] | roster_groups())
|
||||
-> Groups :: [] | roster_groups()
|
||||
).
|
||||
|
||||
filter_groups([] = _Roster_Groups, _Node_Groups, Groups) ->
|
||||
Groups;
|
||||
%%
|
||||
filter_groups([Roster_Group | Roster_Groups], Node_Groups, Groups) ->
|
||||
filter_groups(Roster_Groups, Node_Groups,
|
||||
_Groups = case lists:member(Roster_Group, Node_Groups) of
|
||||
true -> [Roster_Group | Groups];
|
||||
false -> Groups
|
||||
end).
|
||||
|
||||
|
||||
%%
|
||||
-spec(filter_subscriptions/2 ::
|
||||
(
|
||||
Nodes :: n0des(),
|
||||
Roster_Groups :: roster_groups())
|
||||
-> Subscriptions :: [] | subscriptions()
|
||||
).
|
||||
|
||||
filter_subscriptions(Nodes, Roster_Groups) ->
|
||||
_Subscriptions = filter_subscriptions(Nodes, Roster_Groups, []).
|
||||
|
||||
%%
|
||||
-spec(filter_subscriptions/3 ::
|
||||
(
|
||||
Nodes :: n0des(),
|
||||
Roster_Groups :: roster_groups(),
|
||||
Subscriptions :: [] | subscriptions())
|
||||
-> Subscriptions :: [] | subscriptions()
|
||||
).
|
||||
|
||||
filter_subscriptions([] = _Nodes, _Roster_Groups, Subscriptions) ->
|
||||
Subscriptions;
|
||||
%%
|
||||
filter_subscriptions([{NodeIdx, Node_Groups} | Nodes], Roster_Groups,
|
||||
Subscriptions) ->
|
||||
filter_subscriptions(Nodes, Roster_Groups,
|
||||
_Subscriptions = case filter_groups(Roster_Groups, Node_Groups, []) of
|
||||
[] -> Subscriptions;
|
||||
Groups -> [{NodeIdx, Groups} | Subscriptions]
|
||||
end).
|
||||
|
||||
|
||||
%%
|
||||
-spec(diff_nodeidxs/2 ::
|
||||
(
|
||||
New_Subscriptions :: [] | subscriptions(),
|
||||
Old_Subscriptions :: [] | subscriptions())
|
||||
-> Diff_NodeIdxs :: {NodeIdxs_Subscriptions :: [] | nodeIdxs(),
|
||||
NodeIdxs_Unsubscriptions :: [] | nodeIdxs()}
|
||||
).
|
||||
|
||||
diff_nodeidxs(New_Subscriptions, Old_Subscriptions) ->
|
||||
_Diff_NodeIdxs = diff_nodeidxs(New_Subscriptions, Old_Subscriptions, []).
|
||||
|
||||
%%
|
||||
-spec(diff_nodeidxs/3 ::
|
||||
(
|
||||
New_Subscriptions :: [] | subscriptions(),
|
||||
Old_Subscriptions :: [] | subscriptions(),
|
||||
NodeIdxs_Subscriptions :: [] | nodeIdxs())
|
||||
-> Diff_NodeIdxs :: {NodeIdxs_Subscriptions :: [] | nodeIdxs(),
|
||||
NodeIdxs_Unsubscriptions :: [] | nodeIdxs()}
|
||||
).
|
||||
|
||||
diff_nodeidxs([] = _New_Subscriptions, Old_Subscriptions,
|
||||
NodeIdxs_Subscriptions) ->
|
||||
_Diff_NodeIdxs = {
|
||||
_NodeIdxs_Subscriptions = NodeIdxs_Subscriptions,
|
||||
_NodeIdxs_Unsubscriptions = lists:map(fun
|
||||
({NodeIdx, _Roster_Groups}) ->
|
||||
NodeIdx
|
||||
end, Old_Subscriptions)};
|
||||
%%
|
||||
diff_nodeidxs([{NodeIdx, _Groups} | New_Subscriptions], [] = Old_Subscriptions,
|
||||
NodeIdxs_Subscriptions) ->
|
||||
diff_nodeidxs(New_Subscriptions, Old_Subscriptions,
|
||||
[NodeIdx | NodeIdxs_Subscriptions]);
|
||||
%%
|
||||
diff_nodeidxs([{NodeIdx, _Groups} | New_Subscriptions], Old_Subscriptions,
|
||||
NodeIdxs_Subscriptions) ->
|
||||
case lists:keydelete(NodeIdx, 1, Old_Subscriptions) of
|
||||
Old_Subscriptions ->
|
||||
diff_nodeidxs(New_Subscriptions, Old_Subscriptions,
|
||||
[NodeIdx | NodeIdxs_Subscriptions]);
|
||||
Subscriptions ->
|
||||
diff_nodeidxs(New_Subscriptions, _Old_Subscriptions = Subscriptions,
|
||||
NodeIdxs_Subscriptions)
|
||||
end.
|
||||
|
||||
|
||||
%% TODO : use a new mod_roster_api for this call
|
||||
-spec(roster_groups/2 ::
|
||||
(
|
||||
Entity :: xmpp_jid:usr_bare(),
|
||||
Contact :: xmpp_jid:usr_bare())
|
||||
-> Roster_Groups :: [] | roster_groups()
|
||||
).
|
||||
|
||||
roster_groups({User, Server, _} = _Entity, Contact) ->
|
||||
_Roster_Groups = case
|
||||
gen_storage:transaction(Server, rosteritem,
|
||||
fun() ->
|
||||
gen_storage:select(Server, rostergroup,
|
||||
[{'=', user_host_jid, {User, Server, Contact}}])
|
||||
end)
|
||||
of
|
||||
{atomic, _RosterGroups} ->
|
||||
lists:map(fun
|
||||
(_RosterGroup) ->
|
||||
_RosterGroup#roster.groups
|
||||
end, _RosterGroups);
|
||||
_Error
|
||||
-> {error, 'internal-server-error'}
|
||||
end.
|
||||
|
||||
|
||||
%%
|
||||
-spec(select_roster_groups/1 ::
|
||||
(
|
||||
Entity :: xmpp_jid:usr_entity())
|
||||
-> Roster_Groups :: [] | roster_groups()
|
||||
).
|
||||
|
||||
select_roster_groups({User, Server, _} = Entity) ->
|
||||
_Roster_Groups = case
|
||||
gen_storage:transaction(Server, rosteritem,
|
||||
fun() ->
|
||||
gen_storage:select(Server, rostergroup,
|
||||
[{'=', user_host_jid, {User, Server, '_'}}])
|
||||
end)
|
||||
of
|
||||
{atomic, _RosterGroups} ->
|
||||
lists:map(fun
|
||||
(_RosterGroup) ->
|
||||
_RosterGroup#roster.groups
|
||||
end, _RosterGroups);
|
||||
_Error
|
||||
-> {error, 'internal-server-error'}
|
||||
end.
|
||||
|
||||
|
||||
%% TESTS
|
||||
|
||||
%%
|
||||
monitor_roster_groups(Server, Roster) ->
|
||||
?INFO_MSG("SERVER ~p ROSTER ~p", [Server, Roster]),
|
||||
Result = pubsub_db:transaction('mnesia', ?MODULE, monitor_groups,
|
||||
[Server, Roster]),
|
||||
?INFO_MSG("MONITOR ROSTER GROUPS ~p", [Result]).
|
||||
|
||||
|
||||
monitor_contacts2('subscribed', Entity, Jid_Contact) ->
|
||||
Result = pubsub_db:transaction('mnesia', ?MODULE, monitor_contacts,
|
||||
['subscribed', Entity, Jid_Contact]),
|
||||
?INFO_MSG("MONITOR CONTACTS2 ~p", [Result]).
|
||||
|
||||
register1(NodeIdx, User, Groups) ->
|
||||
Server = <<"localhost">>,
|
||||
Owner = {list_to_binary(atom_to_list(User)), Server, undefined},
|
||||
Groups_B = lists:map(fun(Group) -> list_to_binary(atom_to_list(Group)) end, Groups),
|
||||
register_groups(dev, NodeIdx, Owner, Groups_B).
|
||||
|
||||
register(NodeIdx, User, Groups) ->
|
||||
pubsub_db:transaction('mnesia', ?MODULE, register1, [NodeIdx, User, Groups]).
|
||||
@@ -0,0 +1,570 @@
|
||||
%%% ====================================================================
|
||||
%%% ``The contents of this file are subject to the Erlang Public License,
|
||||
%%% Version 1.1, (the "License"); you may not use this file except in
|
||||
%%% compliance with the License. You should have received a copy of the
|
||||
%%% Erlang Public License along with this software. If not, it can be
|
||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||
%%%
|
||||
%%% Software distributed under the License is distributed on an "AS IS"
|
||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
%%% the License for the specific language governing rights and limitations
|
||||
%%% under the License.
|
||||
%%%
|
||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
||||
%%% Portions created by ProcessOne are Copyright 2006-2013, ProcessOne
|
||||
%%% All Rights Reserved.''
|
||||
%%% This software is copyright 2006-2013, ProcessOne.
|
||||
%%%
|
||||
%%% @copyright 2006-2013 ProcessOne
|
||||
%%% @author Karim Gemayel <karim.gemayel@process-one.net>
|
||||
%%% [http://www.process-one.net/]
|
||||
%%% @version {@vsn}, {@date} {@time}
|
||||
%%% @end
|
||||
%%% ====================================================================
|
||||
|
||||
%%% @headerfile "pubsub_dev.hrl"
|
||||
|
||||
-module(pubsub_hooks).
|
||||
-author('karim.gemayel@process-one.net').
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
-include("pubsub_dev.hrl").
|
||||
|
||||
-import(pubsub_tools,
|
||||
[
|
||||
get_option/2,
|
||||
get_option/3,
|
||||
get_value/2,
|
||||
get_value/3,
|
||||
set_value/3,
|
||||
%%
|
||||
check_access_model/3,
|
||||
check_access_model/7,
|
||||
check_publish_model/3,
|
||||
is_contact_subscribed_to_node_owners/3,
|
||||
is_contact_in_allowed_roster_groups/2,
|
||||
has_subscriptions/1
|
||||
]).
|
||||
|
||||
-import(pubsub_db_mnesia,
|
||||
[
|
||||
table/2
|
||||
]).
|
||||
|
||||
%% 'node_config#send_last_published_item'
|
||||
-spec(presence_online/3 ::
|
||||
(
|
||||
From :: xmpp_jid:entity_full(),
|
||||
To :: xmpp_jid:entity_full(),
|
||||
C2SPid :: pid())
|
||||
-> 'ok'
|
||||
).
|
||||
|
||||
presence_online(#jid{luser = U, lserver = S, lresource = R} = Jid, Jid, C2SPid) ->
|
||||
?INFO_MSG("PRESENCE ONLINE From ~p ~n, To ~p ~n, C2SPid ~p ~n",
|
||||
[Jid, Jid, C2SPid]),
|
||||
Pubsub_Features = node_flat_dev:pubsub_features(),
|
||||
case lists:member(<<"last-published">>, Pubsub_Features) of
|
||||
true ->
|
||||
spawn(?MODULE, last_published_items,
|
||||
[_Host = <<"localhost">>, {U,S,R}]);
|
||||
false ->
|
||||
ok
|
||||
end;
|
||||
%%
|
||||
presence_online(_, _, _) ->
|
||||
ok.
|
||||
|
||||
|
||||
%%
|
||||
-spec(last_published_items/2 ::
|
||||
(
|
||||
Host :: xmpp_jid:raw_jid_component_bare(),
|
||||
Entity :: xmpp_jid:usr_full())
|
||||
-> 'ok'
|
||||
).
|
||||
|
||||
last_published_items(Host, {U,S,_R} = Entity) ->
|
||||
Table_Pubsub_State = table('pubsub_state', 'dev'),
|
||||
Table_Pubsub_Node = table('pubsub_node', 'dev'),
|
||||
Table_Pubsub_Last_Item = table('pubsub_last_item', 'dev'),
|
||||
lists:foreach(fun
|
||||
(State) ->
|
||||
last_published_items(Host, Entity, Table_Pubsub_Node,
|
||||
Table_Pubsub_Last_Item, State)
|
||||
end,
|
||||
mnesia:dirty_select(Table_Pubsub_State,
|
||||
[{#pubsub_state_dev{
|
||||
id = {{U,S,undefined}, '$1'},
|
||||
affiliation = '$2',
|
||||
access = '$3',
|
||||
subscriptions = '$4',
|
||||
_ = '_'
|
||||
},
|
||||
[{'=/=', '$2', 'outcast'},
|
||||
{'=/=', '$3', 'pending'},
|
||||
{'=/=', '$4', []}],
|
||||
['$$']}])).
|
||||
|
||||
%%
|
||||
-spec(last_published_items/5 ::
|
||||
(
|
||||
Host :: xmpp_jid:raw_jid_component_bare(),
|
||||
Entity :: xmpp_jid:usr_full(),
|
||||
Table_Pubsub_Node :: atom(),
|
||||
Table_Pubsub_Last_Item :: atom(),
|
||||
State :: [exmpp_pubsub:nodeIdx() |
|
||||
'member' | 'owner' | 'publisher' |
|
||||
_ |
|
||||
exmpp_pubsub:subscriptions(),... ])
|
||||
-> 'ok'
|
||||
).
|
||||
|
||||
last_published_items(Host, {_, _, Online_Resource} = Entity,
|
||||
Table_Pubsub_Node, Table_Pubsub_Last_Item,
|
||||
[NodeIdx, Affiliation, _Access, Subscriptions]) ->
|
||||
case mnesia:dirty_index_read(Table_Pubsub_Node, NodeIdx, idx) of
|
||||
[#pubsub_node_dev{
|
||||
id = {Pubsub_Host, NodeId},
|
||||
owners = Node_Owners,
|
||||
options = Node_Options
|
||||
}] ->
|
||||
case get_value(Node_Options, 'send_last_published_item') of
|
||||
'on_sub_and_presence' ->
|
||||
case mnesia:dirty_read(Table_Pubsub_Last_Item, NodeIdx) of
|
||||
[#pubsub_last_item_dev{
|
||||
id = ItemId,
|
||||
creation = {DateTime, Publisher},
|
||||
payload = Payload,
|
||||
options = Item_Options
|
||||
}] ->
|
||||
spawn(pubsub_broadcast, broadcast_publish_last2,
|
||||
[Host, Pubsub_Host, NodeId, Node_Options,
|
||||
Node_Owners,
|
||||
[{ItemId, Item_Options, Payload, Publisher, DateTime}],
|
||||
Entity, Affiliation,
|
||||
lists:foldl(fun
|
||||
({Subscription_State, SubId, Resource, Subscription_Options},
|
||||
Acc)
|
||||
when Subscription_State =/= 'pending'
|
||||
andalso (Resource == undefined
|
||||
orelse
|
||||
Resource == Online_Resource) ->
|
||||
[{Subscription_State, SubId,
|
||||
Online_Resource, Subscription_Options}
|
||||
| Acc];
|
||||
(_Subscription, Acc) ->
|
||||
Acc
|
||||
end, [], Subscriptions)]);
|
||||
_ ->
|
||||
ok
|
||||
end;
|
||||
_ ->
|
||||
ok
|
||||
end;
|
||||
_ ->
|
||||
ok
|
||||
end.
|
||||
|
||||
%% 'node_config#purge_offline'
|
||||
%% 'node_config#tempsub'
|
||||
%% 'subscribe_options#expire'
|
||||
|
||||
-spec(presence_offline/3 ::
|
||||
(
|
||||
_ :: _,
|
||||
Jid :: xmpp_jid:entity_full(),
|
||||
_ :: _)
|
||||
-> 'ok'
|
||||
).
|
||||
|
||||
presence_offline({_DateTime, _Pid},
|
||||
#jid{luser = U, lserver = S, lresource = Offline_Resource} = _Jid, _) ->
|
||||
Host = <<"localhost">>,
|
||||
Pubsub_Features = node_flat_dev:pubsub_features(),
|
||||
Subscribe = lists:member(<<"subscribe">>, Pubsub_Features),
|
||||
Leased_Subscription = lists:member(<<"leased-subscription">>, Pubsub_Features),
|
||||
Purge_Nodes = lists:member(<<"purge-nodes">>, Pubsub_Features),
|
||||
Persistent_Items = lists:member(<<"persistent-items">>, Pubsub_Features),
|
||||
Subscription_Notifications = lists:member(<<"subscription-notifications">>,
|
||||
Pubsub_Features),
|
||||
Table_Pubsub_State = table('pubsub_state', 'dev'),
|
||||
Table_Pubsub_Node = table('pubsub_node', 'dev'),
|
||||
Online_Resources = case ejabberd_sm:get_user_resources(U, S) of
|
||||
[] -> false;
|
||||
_ -> true
|
||||
end,
|
||||
lists:foreach(fun
|
||||
(Pubsub_State) ->
|
||||
presence_offline(Host,
|
||||
_Entity = {U,S,undefined},
|
||||
Table_Pubsub_State,
|
||||
Pubsub_State,
|
||||
Table_Pubsub_Node,
|
||||
Offline_Resource,
|
||||
Online_Resources,
|
||||
{Subscribe,
|
||||
Leased_Subscription,
|
||||
Purge_Nodes,
|
||||
Persistent_Items,
|
||||
Subscription_Notifications})
|
||||
end,
|
||||
mnesia:dirty_match_object(Table_Pubsub_State,
|
||||
#pubsub_state_dev{
|
||||
id = {{U,S,undefined}, '_'},
|
||||
_ = '_'
|
||||
})).
|
||||
|
||||
%%
|
||||
-spec(presence_offline/8 ::
|
||||
(
|
||||
Host :: xmpp_jid:raw_jid_component_bare(),
|
||||
Entity :: xmpp_jid:usr_bare(),
|
||||
Table_Pubsub_State :: atom(),
|
||||
Pubsub_State :: mod_pubsub_dev:pubsub_state(),
|
||||
Table_Pubsub_Node :: atom(),
|
||||
Offline_Resource :: xmpp_jid:resource_jid(),
|
||||
Online_Resources :: boolean(),
|
||||
Pubsub_Features :: {Subscribe :: boolean(),
|
||||
Leased_Subscription :: boolean(),
|
||||
Purge_Nodes :: boolean(),
|
||||
Persistent_Items :: boolean(),
|
||||
Subscription_Notifications :: boolean()})
|
||||
-> 'ok'
|
||||
).
|
||||
|
||||
presence_offline(Host, Entity, Table_Pubsub_State, Pubsub_State,
|
||||
Table_Pubsub_Node, Offline_Resource, Online_Resources,
|
||||
{Subscribe, Leased_Subscription, Purge_Nodes, Persistent_Items,
|
||||
Subscription_Notifications}) ->
|
||||
case
|
||||
mnesia:dirty_index_read(Table_Pubsub_Node,
|
||||
Pubsub_State#pubsub_state_dev.nodeidx, idx)
|
||||
of
|
||||
[#pubsub_node_dev{id = {Pubsub_Host, NodeId}} = Pubsub_Node] ->
|
||||
Node_Options = Pubsub_Node#pubsub_node_dev.options,
|
||||
|
||||
case
|
||||
Subscribe == true
|
||||
andalso
|
||||
get_value(Node_Options, 'tempsub') == true
|
||||
of
|
||||
true ->
|
||||
case
|
||||
filter_tempsub_subscriptions(
|
||||
get_value(Node_Options, 'notify_sub'),
|
||||
Pubsub_State#pubsub_state_dev.subscriptions,
|
||||
Offline_Resource, Online_Resources, {[], []})
|
||||
of
|
||||
%%
|
||||
{_Unexpired_Subscriptions, [] = _Expired_Subscriptions} ->
|
||||
ok;
|
||||
%%
|
||||
{[] = _Unexpired_Subscriptions, Expired_Subscriptions}
|
||||
when Pubsub_State#pubsub_state_dev.affiliation == 'member'
|
||||
andalso Pubsub_State#pubsub_state_dev.itemids == [] ->
|
||||
mnesia:dirty_delete_object(Table_Pubsub_State,
|
||||
Pubsub_State),
|
||||
Notification_Type = get_value(Node_Options,
|
||||
'notification_type', 'headline'),
|
||||
notify_subscriptions(Host, Pubsub_Host,
|
||||
Entity, NodeId, Notification_Type,
|
||||
_Recipients = case Subscription_Notifications of
|
||||
true ->
|
||||
case
|
||||
lists:member(Entity,
|
||||
Pubsub_Node#pubsub_node_dev.owners)
|
||||
of
|
||||
true ->
|
||||
Pubsub_Node#pubsub_node_dev.owners;
|
||||
false ->
|
||||
[Entity
|
||||
| Pubsub_Node#pubsub_node_dev.owners]
|
||||
end;
|
||||
false ->
|
||||
Pubsub_Node#pubsub_node_dev.owners
|
||||
end,
|
||||
Expired_Subscriptions),
|
||||
ok;
|
||||
%%
|
||||
{Unexpired_Subscriptions, Expired_Subscriptions} ->
|
||||
mnesia:dirty_write(Table_Pubsub_State,
|
||||
Pubsub_State#pubsub_state_dev{
|
||||
subscriptions = Unexpired_Subscriptions
|
||||
}),
|
||||
Notification_Type = get_value(Node_Options,
|
||||
'notification_type', 'headline'),
|
||||
notify_subscriptions(Host, Pubsub_Host,
|
||||
Entity, NodeId, Notification_Type,
|
||||
_Recipients = case Subscription_Notifications of
|
||||
true ->
|
||||
case
|
||||
lists:member(Entity,
|
||||
Pubsub_Node#pubsub_node_dev.owners)
|
||||
of
|
||||
true ->
|
||||
Pubsub_Node#pubsub_node_dev.owners;
|
||||
false ->
|
||||
[Entity
|
||||
| Pubsub_Node#pubsub_node_dev.owners]
|
||||
end;
|
||||
false ->
|
||||
Pubsub_Node#pubsub_node_dev.owners
|
||||
end,
|
||||
Expired_Subscriptions),
|
||||
ok
|
||||
end;
|
||||
_ ->
|
||||
case Subscribe == true andalso Leased_Subscription == true of
|
||||
true ->
|
||||
case
|
||||
filter_expired_subscriptions(
|
||||
get_value(Node_Options, 'notify_sub'),
|
||||
Pubsub_State#pubsub_state_dev.subscriptions,
|
||||
Offline_Resource, Online_Resources, {[], []})
|
||||
of
|
||||
%%
|
||||
{_Unexpired_Subscriptions, [] = _Expired_Subscriptions} ->
|
||||
ok;
|
||||
%%
|
||||
{[] = _Unexpired_Subscriptions, Expired_Subscriptions}
|
||||
when Pubsub_State#pubsub_state_dev.affiliation == 'member' ->
|
||||
mnesia:dirty_delete_object(Table_Pubsub_State,
|
||||
Pubsub_State),
|
||||
Notification_Type = get_value(Node_Options,
|
||||
'notification_type', 'headline'),
|
||||
notify_subscriptions(Host, Pubsub_Host,
|
||||
Entity, NodeId, Notification_Type,
|
||||
_Recipients = case
|
||||
Subscription_Notifications
|
||||
of
|
||||
true ->
|
||||
case
|
||||
lists:member(Entity,
|
||||
Pubsub_Node#pubsub_node_dev.owners)
|
||||
of
|
||||
true ->
|
||||
Pubsub_Node#pubsub_node_dev.owners;
|
||||
false ->
|
||||
[Entity
|
||||
|Pubsub_Node#pubsub_node_dev.owners]
|
||||
end;
|
||||
false ->
|
||||
Pubsub_Node#pubsub_node_dev.owners
|
||||
end,
|
||||
Expired_Subscriptions),
|
||||
ok;
|
||||
%%
|
||||
{Unexpired_Subscriptions, Expired_Subscriptions} ->
|
||||
mnesia:dirty_write(Table_Pubsub_State,
|
||||
Pubsub_State#pubsub_state_dev{
|
||||
subscriptions = Unexpired_Subscriptions
|
||||
}),
|
||||
Notification_Type = get_value(Node_Options,
|
||||
'notification_type', 'headline'),
|
||||
notify_subscriptions(Host, Pubsub_Host,
|
||||
Entity, NodeId, Notification_Type,
|
||||
_Recipients = case
|
||||
Subscription_Notifications
|
||||
of
|
||||
true ->
|
||||
case
|
||||
lists:member(Entity,
|
||||
Pubsub_Node#pubsub_node_dev.owners)
|
||||
of
|
||||
true ->
|
||||
Pubsub_Node#pubsub_node_dev.owners;
|
||||
false ->
|
||||
[Entity
|
||||
| Pubsub_Node#pubsub_node_dev.owners]
|
||||
end;
|
||||
false ->
|
||||
Pubsub_Node#pubsub_node_dev.owners
|
||||
end,
|
||||
Expired_Subscriptions),
|
||||
ok
|
||||
end;
|
||||
false ->
|
||||
ok
|
||||
end
|
||||
end;
|
||||
[] ->
|
||||
ok
|
||||
end.
|
||||
|
||||
%%
|
||||
-spec(notify_subscriptions/7 ::
|
||||
(
|
||||
Host :: xmpp_jid:raw_jid_component_bare(),
|
||||
Pubsub_Host :: exmpp_pubsub:host(),
|
||||
Entity :: xmpp_jid:usr_bare(),
|
||||
NodeId :: exmpp_pubsub:nodeId(),
|
||||
Notification_Type :: 'message' | 'headline',
|
||||
Recipients :: [Entity::xmpp_jid:usr_bare(),...],
|
||||
Subscriptions :: [Subscription::exmpp_pubsub:subscription(),...])
|
||||
-> 'ok'
|
||||
).
|
||||
|
||||
notify_subscriptions(Host, Pubsub_Host, {U,S,_} = _Entity, NodeId,
|
||||
Notification_Type, Recipients, Subscriptions) ->
|
||||
Pubsub_Component_Jid = jlib:make_jid(<<>>, Pubsub_Host, <<>>),
|
||||
Jids = [pubsub_tools:make_jid(Recipient) || Recipient <- Recipients],
|
||||
lists:foreach(fun
|
||||
({_, SubId, Resource, _}) ->
|
||||
Subscriber = jlib:jid_to_string({U,S,Resource}),
|
||||
lists:foreach(fun
|
||||
(Recipient) ->
|
||||
spawn(pubsub_broadcast, notify_subscription,
|
||||
[Host, NodeId, Pubsub_Component_Jid, Recipient,
|
||||
Notification_Type, {Subscriber, 'none', SubId}])
|
||||
end, Jids)
|
||||
end, Subscriptions).
|
||||
|
||||
%%
|
||||
filter_purged_offline_itemids([Publisher_ItemId | Publisher_ItemIds],
|
||||
Table_Pubsub_Item, NodeIdx, {U,S,R} = _Entity,
|
||||
{Node_ItemIds, Unpurged_ItemIds, Purged_ItemIds}) ->
|
||||
filter_purged_offline_itemids(Publisher_ItemIds, Table_Pubsub_Item, NodeIdx,
|
||||
{U,S,R},
|
||||
case
|
||||
mnesia:dirty_index_match_object(Table_Pubsub_Item,
|
||||
#pubsub_item_dev{
|
||||
id = {Publisher_ItemId, NodeIdx},
|
||||
nodeidx = NodeIdx,
|
||||
_ = '_'
|
||||
},
|
||||
nodeidx)
|
||||
of
|
||||
[#pubsub_item_dev{creation = {_DateTime, {U,S,_}}} = Pubsub_Item] ->
|
||||
mnesia:dirty_delete_object(Table_Pubsub_Item, Pubsub_Item);
|
||||
_ ->
|
||||
{Node_ItemIds,
|
||||
[Publisher_ItemId | Unpurged_ItemIds],
|
||||
Purged_ItemIds}
|
||||
end).
|
||||
|
||||
|
||||
%%
|
||||
-spec(filter_tempsub_subscriptions/5 ::
|
||||
(
|
||||
Notify_Sub :: boolean() | 'none',
|
||||
Subscriptions :: [] | exmpp_pubsub:subscriptions(),
|
||||
Offline_Resource :: xmpp_jid:resource_jid(),
|
||||
Online_Resources :: boolean(),
|
||||
Filtered_TempSub_Subscriptions :: {
|
||||
Unexpired_Subscriptions :: [] | exmpp_pubsub:subscriptions(),
|
||||
Expired_Subscriptions :: [] | exmpp_pubsub:subscriptions()
|
||||
})
|
||||
-> Filtered_TempSub_Subscriptions :: {
|
||||
Unexpired_Subscriptions :: [] | exmpp_pubsub:subscriptions(),
|
||||
Expired_Subscriptions :: [] | exmpp_pubsub:subscriptions()
|
||||
}
|
||||
).
|
||||
|
||||
filter_tempsub_subscriptions(_Notify_Sub, [] = _Subscriptions,
|
||||
_Offline_Resource, _Online_Resources, Filtered_TempSub_Subscriptions) ->
|
||||
Filtered_TempSub_Subscriptions;
|
||||
%%
|
||||
filter_tempsub_subscriptions(Notify_Sub,
|
||||
[{Subscription_State, SubId, Resource, Subscription_Options} | Subscriptions],
|
||||
Offline_Resource, Online_Resources,
|
||||
{Unexpired_Subscriptions, Expired_Subscriptions})
|
||||
when ((Online_Resources == false
|
||||
andalso
|
||||
(Resource == undefined orelse Resource == Offline_Resource))
|
||||
orelse
|
||||
(Online_Resources == true
|
||||
andalso
|
||||
Resource == Offline_Resource)) ->
|
||||
filter_tempsub_subscriptions(Notify_Sub, Subscriptions, Offline_Resource,
|
||||
Online_Resources,
|
||||
{Unexpired_Subscriptions,
|
||||
_Expired_Subscriptions = case Notify_Sub of
|
||||
true ->
|
||||
[{Subscription_State, SubId, Resource, Subscription_Options}
|
||||
| Expired_Subscriptions];
|
||||
_ ->
|
||||
Expired_Subscriptions
|
||||
end});
|
||||
%%
|
||||
filter_tempsub_subscriptions(Notify_Sub, [Subscription | Subscriptions],
|
||||
Offline_Resource, Online_Resources,
|
||||
{Unexpired_Subscriptions, Expired_Subscriptions}) ->
|
||||
filter_tempsub_subscriptions(Notify_Sub, Subscriptions, Offline_Resource,
|
||||
Online_Resources,
|
||||
{[Subscription | Unexpired_Subscriptions], Expired_Subscriptions}).
|
||||
|
||||
%%
|
||||
-spec(filter_expired_subscriptions/5 ::
|
||||
(
|
||||
Notify_Sub :: boolean() | 'none',
|
||||
Subscriptions :: [] | exmpp_pubsub:subscriptions(),
|
||||
Offline_Resource :: xmpp_jid:resource_jid(),
|
||||
Online_Resources :: boolean(),
|
||||
Filtered_Expired_Subscriptions :: {
|
||||
Unexpired_Subscriptions :: [] | exmpp_pubsub:subscriptions(),
|
||||
Expired_Subscriptions :: [] | exmpp_pubsub:subscriptions()
|
||||
})
|
||||
-> Filtered_Expired_Subscriptions :: {
|
||||
Unexpired_Subscriptions :: [] | exmpp_pubsub:subscriptions(),
|
||||
Expired_Subscriptions :: [] | exmpp_pubsub:subscriptions()
|
||||
}
|
||||
).
|
||||
|
||||
filter_expired_subscriptions(_Notify_Sub, [] = _Subscriptions, _Offline_Resource,
|
||||
_Online_Resources, Filtered_Expired_Subscriptions) ->
|
||||
Filtered_Expired_Subscriptions;
|
||||
%%
|
||||
filter_expired_subscriptions(Notify_Sub,
|
||||
[{Subscription_State, SubId, Resource, Subscription_Options} | Subscriptions],
|
||||
Offline_Resource, Online_Resources,
|
||||
{Unexpired_Subscriptions, Expired_Subscriptions})
|
||||
when Subscription_Options =/= []
|
||||
andalso ((Online_Resources == false
|
||||
andalso
|
||||
(Resource == undefined orelse Resource == Offline_Resource))
|
||||
orelse
|
||||
(Online_Resources == true
|
||||
andalso
|
||||
Resource == Offline_Resource)) ->
|
||||
filter_expired_subscriptions(Notify_Sub, Subscriptions, Offline_Resource,
|
||||
Online_Resources,
|
||||
case get_value(Subscription_Options, 'expire') of
|
||||
'presence' ->
|
||||
{Unexpired_Subscriptions,
|
||||
_Expired_Subscriptions = case Notify_Sub of
|
||||
true ->
|
||||
[{Subscription_State, SubId, Resource, Subscription_Options}
|
||||
| Expired_Subscriptions];
|
||||
false ->
|
||||
Expired_Subscriptions
|
||||
end};
|
||||
_ ->
|
||||
{[{Subscription_State, SubId, Resource, Subscription_Options}
|
||||
| Unexpired_Subscriptions],
|
||||
Expired_Subscriptions}
|
||||
end);
|
||||
%%
|
||||
filter_expired_subscriptions(Notify_Sub, [Subscription | Subscriptions],
|
||||
Offline_Resource, Online_Resources,
|
||||
{Unexpired_Subscriptions, Expired_Subscriptions}) ->
|
||||
filter_expired_subscriptions(Notify_Sub, Subscriptions, Offline_Resource,
|
||||
Online_Resources,
|
||||
{[Subscription | Unexpired_Subscriptions], Expired_Subscriptions}).
|
||||
|
||||
|
||||
%%
|
||||
roster_process_item(Roster_Item, Server) ->
|
||||
spawn(pubsub_groups, monitor_roster_groups, [Server, Roster_Item]),
|
||||
Roster_Item.
|
||||
|
||||
|
||||
|
||||
roster_in_subscription(Boolean, User, Server, Jid_Contact,
|
||||
'subscribed' = _Subscription_Type) ->
|
||||
spawn(pubsub_groups, monitor_contacts2,
|
||||
['subscribed', {User, Server, undefined}, Jid_Contact]),
|
||||
Boolean;
|
||||
roster_in_subscription(Boolean, _User, _Server, _JID, _SubscriptionType) ->
|
||||
Boolean.
|
||||
@@ -0,0 +1,113 @@
|
||||
%%% ====================================================================
|
||||
%%% ``The contents of this file are subject to the Erlang Public License,
|
||||
%%% Version 1.1, (the "License"); you may not use this file except in
|
||||
%%% compliance with the License. You should have received a copy of the
|
||||
%%% Erlang Public License along with this software. If not, it can be
|
||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||
%%%
|
||||
%%% Software distributed under the License is distributed on an "AS IS"
|
||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
%%% the License for the specific language governing rights and limitations
|
||||
%%% under the License.
|
||||
%%%
|
||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
||||
%%% Portions created by ProcessOne are Copyright 2006-2013, ProcessOne
|
||||
%%% All Rights Reserved.''
|
||||
%%% This software is copyright 2006-2013, ProcessOne.
|
||||
%%%
|
||||
%%%
|
||||
%%% @copyright 2006-2013 ProcessOne
|
||||
%%% @author Christophe Romain <christophe.romain@process-one.net>
|
||||
%%% [http://www.process-one.net/]
|
||||
%%% @version {@vsn}, {@date} {@time}
|
||||
%%% @end
|
||||
%%% ====================================================================
|
||||
|
||||
%% important note:
|
||||
%% new/1 and free/2 MUST be called inside a transaction bloc
|
||||
|
||||
-module(pubsub_index_dev).
|
||||
-author('christophe.romain@process-one.net').
|
||||
|
||||
-include("pubsub_dev.hrl").
|
||||
|
||||
-export([
|
||||
init/1,
|
||||
new/2,
|
||||
free/3
|
||||
]).
|
||||
|
||||
-import(pubsub_db_mnesia,
|
||||
[
|
||||
table/2
|
||||
]).
|
||||
|
||||
|
||||
%%
|
||||
-spec(init/1 ::
|
||||
(
|
||||
Suffix::atom()) -> 'ok'
|
||||
).
|
||||
|
||||
init(Suffix) ->
|
||||
mnesia:create_table(table('pubsub_index_dev', Suffix),
|
||||
[{disc_copies, [node()]},
|
||||
{record_name, pubsub_index_dev},
|
||||
{attributes, record_info(fields, pubsub_index_dev)}]).
|
||||
|
||||
%%
|
||||
-spec(new/2 ::
|
||||
(
|
||||
Suffix :: atom(),
|
||||
Index :: exmpp_pubsub:index())
|
||||
-> Idx::exmpp_pubsub:nodeIdx()
|
||||
).
|
||||
|
||||
new(Suffix, Index) ->
|
||||
case
|
||||
mnesia:read(Table_Pubsub_Index = table('pubsub_index_dev', Suffix),
|
||||
Index, write)
|
||||
of
|
||||
[#pubsub_index_dev{free = []} = Pubsub_Index] ->
|
||||
mnesia:write(Table_Pubsub_Index,
|
||||
Pubsub_Index#pubsub_index_dev{
|
||||
last = Idx = Pubsub_Index#pubsub_index_dev.last + 1
|
||||
},
|
||||
write),
|
||||
Idx;
|
||||
[#pubsub_index_dev{free = [Idx|Free]} = Pubsub_Index] ->
|
||||
mnesia:write(Table_Pubsub_Index,
|
||||
Pubsub_Index#pubsub_index_dev{
|
||||
free = Free
|
||||
},
|
||||
write),
|
||||
Idx;
|
||||
_ ->
|
||||
mnesia:write(Table_Pubsub_Index,
|
||||
#pubsub_index_dev{index = Index, last = 1, free = []}, write),
|
||||
1
|
||||
end.
|
||||
|
||||
%%
|
||||
-spec(free/3 ::
|
||||
(
|
||||
Suffix :: atom(),
|
||||
Index :: exmpp_pubsub:index(),
|
||||
Idx :: exmpp_pubsub:nodeIdx())
|
||||
-> 'ok'
|
||||
).
|
||||
|
||||
free(Suffix, Index, Idx) ->
|
||||
case
|
||||
mnesia:read(Table_Pubsub_Index = table('pubsub_index_dev', Suffix),
|
||||
Index, write)
|
||||
of
|
||||
[Pubsub_Index] ->
|
||||
mnesia:write(Table_Pubsub_Index,
|
||||
Pubsub_Index#pubsub_index_dev{
|
||||
free = [Idx | Pubsub_Index#pubsub_index_dev.free]
|
||||
},
|
||||
write);
|
||||
_ ->
|
||||
ok
|
||||
end.
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,685 @@
|
||||
%%% ====================================================================
|
||||
%%% ``The contents of this file are subject to the Erlang Public License,
|
||||
%%% Version 1.1, (the "License"); you may not use this file except in
|
||||
%%% compliance with the License. You should have received a copy of the
|
||||
%%% Erlang Public License along with this software. If not, it can be
|
||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||
%%%
|
||||
%%% Software distributed under the License is distributed on an "AS IS"
|
||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
%%% the License for the specific language governing rights and limitations
|
||||
%%% under the License.
|
||||
%%%
|
||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
||||
%%% Portions created by ProcessOne are Copyright 2006-2013, ProcessOne
|
||||
%%% All Rights Reserved.''
|
||||
%%% This software is copyright 2006-2013, ProcessOne.
|
||||
%%%
|
||||
%%% @copyright 2006-2013 ProcessOne
|
||||
%%% @author Karim Gemayel <karim.gemayel@process-one.net>
|
||||
%%% [http://www.process-one.net/]
|
||||
%%% @version {@vsn}, {@date} {@time}
|
||||
%%% @end
|
||||
%%% ====================================================================
|
||||
|
||||
%%% @headerfile "pubsub_dev.hrl"
|
||||
|
||||
-module(pubsub_tools).
|
||||
-author('karim.gemayel@process-one.net').
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
-include("pubsub_dev.hrl").
|
||||
|
||||
jid_to_string({undefined, S, undefined}) ->
|
||||
jlib:jid_to_string({<<>>, S, <<>>});
|
||||
jid_to_string({undefined, S, R}) ->
|
||||
jlib:jid_to_string({<<>>, S, R});
|
||||
jid_to_string({U, S, undefined}) ->
|
||||
jlib:jid_to_string({U, S, <<>>});
|
||||
jid_to_string(USR) ->
|
||||
jlib:jid_to_string(USR).
|
||||
|
||||
make_jid({undefined, S, undefined}) ->
|
||||
jlib:make_jid(<<>>, S, <<>>);
|
||||
make_jid({U, S, undefined}) ->
|
||||
jlib:make_jid({U, S, <<>>});
|
||||
make_jid(Entity) ->
|
||||
jlib:make_jid(Entity).
|
||||
|
||||
%% @doc Determine if data is a JID
|
||||
-spec(is_jid/1 ::
|
||||
(
|
||||
Data :: binary() | undefined)
|
||||
-> xmpp_jid:entity() | {error, 'jid-malformed'}
|
||||
).
|
||||
|
||||
is_jid(Data) ->
|
||||
try jlib:string_to_jid(Data) of
|
||||
#jid{} = Jid -> Jid
|
||||
catch
|
||||
_Error -> {error, 'jid-malformed'}
|
||||
end.
|
||||
|
||||
%%%
|
||||
%-spec(get_value/2 ::
|
||||
%(
|
||||
% Options :: {Node_Options :: pubsub_options:options_node(),
|
||||
% Item_Options :: [] | pubsub_options:options_item()}
|
||||
% | pubsub_options:options_item()
|
||||
% | pubsub_options:options_node()
|
||||
% | pubsub_options:options_subscription()
|
||||
% | [],
|
||||
% Key :: atom())
|
||||
% -> Value :: atom()
|
||||
% | binary()
|
||||
% | boolean()
|
||||
% | non_neg_integer()
|
||||
% | undefined
|
||||
% | []
|
||||
% | 'none'
|
||||
% | [atom(),...]
|
||||
% | [binary(),...]
|
||||
% | [boolean(),...]
|
||||
% | [non_neg_integer(),...]
|
||||
%).
|
||||
|
||||
get_value({Node_Options, [] = _Item_Options}, Key) ->
|
||||
get_value(Node_Options, Key, 0);
|
||||
%%
|
||||
get_value({Node_Options, Item_Options}, Key) ->
|
||||
case get_value(Item_Options, Key, 'none') of
|
||||
'none' -> get_value(Node_Options, Key, false);
|
||||
Value -> Value
|
||||
end;
|
||||
%%
|
||||
get_value([], _Key) -> 'none';
|
||||
%%
|
||||
get_value(Options, Key) ->
|
||||
get_value(Options, Key, 'none').
|
||||
|
||||
%%%
|
||||
%-spec(get_value/3 ::
|
||||
%(
|
||||
% Options :: {Node_Options :: pubsub_options:options_node(),
|
||||
% Item_Options :: [] | pubsub_options:options_item()}
|
||||
% | pubsub_options:options_item()
|
||||
% | pubsub_options:options_node()
|
||||
% | pubsub_options:options_subscription(),
|
||||
% Key :: atom(),
|
||||
% Default :: term())
|
||||
% -> Value :: atom()
|
||||
% | binary()
|
||||
% | boolean()
|
||||
% | non_neg_integer()
|
||||
% | undefined
|
||||
% | []
|
||||
% | [atom(),...]
|
||||
% | [binary(),...]
|
||||
% | [boolean(),...]
|
||||
% | [non_neg_integer(),...]
|
||||
%).
|
||||
get_value({Node_Options, [] = _Item_Options}, Key, Default) ->
|
||||
get_value(Node_Options, Key, Default);
|
||||
%%
|
||||
get_value({Node_Options, Item_Options}, Key, Default) ->
|
||||
case get_value(Item_Options, Key, 'none') of
|
||||
'none' -> get_value(Node_Options, Key, Default);
|
||||
Value -> Value
|
||||
end;
|
||||
%%
|
||||
get_value(Options, Key, Default) ->
|
||||
case lists:keyfind(Key, 1, Options) of
|
||||
{_Key, Value} -> Value;
|
||||
false -> Default
|
||||
end.
|
||||
|
||||
%%%
|
||||
%-spec(set_value/3 ::
|
||||
%(
|
||||
% Options :: pubsub_options:options_item()
|
||||
% | pubsub_options:options_node()
|
||||
% | pubsub_options:options_subscription(),
|
||||
% Key :: atom(),
|
||||
% Value :: atom()
|
||||
% | binary()
|
||||
% | boolean()
|
||||
% | non_neg_integer()
|
||||
% | undefined
|
||||
% | []
|
||||
% | [atom(),...]
|
||||
% | [binary(),...]
|
||||
% | [boolean(),...]
|
||||
% | [non_neg_integer(),...])
|
||||
% -> Options :: pubsub_options:options_item()
|
||||
% | pubsub_options:options_node()
|
||||
% | pubsub_options:options_subscription()
|
||||
%).
|
||||
|
||||
set_value(Options, Key, Value) ->
|
||||
lists:keyreplace(Key, 1, Options, {Key, Value}).
|
||||
|
||||
%%
|
||||
|
||||
%-spec(get_option/2 ::
|
||||
%(
|
||||
% Options :: {Node_Options :: pubsub_options:options_node(),
|
||||
% Item_Options :: [] | pubsub_options:options_item()}
|
||||
% | pubsub_options:options_item()
|
||||
% | pubsub_options:options_node()
|
||||
% | pubsub_options:options_subscription()
|
||||
% | [],
|
||||
% Key :: atom())
|
||||
% -> Option :: pubsub_options:option_item()
|
||||
% | pubsub_options:option_node()
|
||||
% | pubsub_options:option_subscription()
|
||||
% | 'none'
|
||||
%).
|
||||
|
||||
get_option({Node_Options, [] = _Item_Options}, Key) ->
|
||||
get_option(Node_Options, Key, 'none');
|
||||
%%
|
||||
get_option({Node_Options, Item_Options}, Key) ->
|
||||
case get_option(Item_Options, Key, 'none') of
|
||||
'none' -> get_option(Node_Options, Key, 'none');
|
||||
Option -> Option
|
||||
end;
|
||||
%%
|
||||
get_option([], _Key) -> 'none';
|
||||
%%
|
||||
get_option(Options, Key) ->
|
||||
get_option(Options, Key, 'none').
|
||||
|
||||
%%%
|
||||
%-spec(get_option/3 ::
|
||||
%(
|
||||
% Options :: {Node_Options :: pubsub_options:options_node(),
|
||||
% Item_Options :: [] | pubsub_options:options_item()}
|
||||
% | pubsub_options:options_item()
|
||||
% | pubsub_options:options_node()
|
||||
% | pubsub_options:options_subscription(),
|
||||
% Key :: atom(),
|
||||
% Default :: term())
|
||||
% -> Option :: pubsub_options:option_item()
|
||||
% | pubsub_options:option_node()
|
||||
% | pubsub_options:option_subscription()
|
||||
% | term()
|
||||
%).
|
||||
|
||||
get_option({Node_Options, [] = _Item_Options}, Key, Default) ->
|
||||
get_option(Node_Options, Key, Default);
|
||||
%%
|
||||
get_option({Node_Options, Item_Options}, Key, Default) ->
|
||||
case get_option(Item_Options, Key, 'none') of
|
||||
'none' -> get_option(Node_Options, Key, Default);
|
||||
Option -> Option
|
||||
end;
|
||||
%%
|
||||
get_option(Options, Key, Default) ->
|
||||
case lists:keyfind(Key, 1, Options) of
|
||||
{_Key, Value} -> _Option = {Key, Value};
|
||||
false -> Default
|
||||
end.
|
||||
|
||||
%%
|
||||
-spec(get_entity_roster/1 ::
|
||||
(
|
||||
Entity :: xmpp_jid:usr_entity()
|
||||
| xmpp_jid:entity())
|
||||
-> Roster::[Roster_Item::#roster{}]
|
||||
).
|
||||
|
||||
get_entity_roster({U,S, _R} = _USR_Entity) ->
|
||||
_Roster = ejabberd_hooks:run_fold(roster_get, S, [], [{U,S}]);
|
||||
get_entity_roster(#jid{luser = U, lserver = S} = _Jid_Entity) ->
|
||||
_Roster = get_entity_roster({U,S, undefined}).
|
||||
|
||||
%%
|
||||
-spec(check_access_model/3 ::
|
||||
(
|
||||
Host :: xmpp_jid:raw_jid_component_bare(),
|
||||
Entity :: xmpp_jid:usr_entity(),
|
||||
Criteria :: {Access_Model :: pubsub_options:access_model(),
|
||||
Affiliation :: exmpp_pubsub:affiliation(),
|
||||
Subscriptions :: exmpp_pubsub:subscriptions(),
|
||||
Node_Owners :: [Node_Owner::xmpp_jid:usr_bare(),...],
|
||||
Rosters_Groups_Allowed :: pubsub_options:rosters_groups_allowed()})
|
||||
-> ok
|
||||
%%%
|
||||
| {error, 'forbidden'}
|
||||
).
|
||||
|
||||
check_access_model(_Host, _Entity,
|
||||
{_Access_Model, 'outcast' = _Affiliation, _Subscriptions, _Node_Owners,
|
||||
_Rosters_Groups_Allowed}) ->
|
||||
{error, 'forbidden'};
|
||||
%%
|
||||
check_access_model(_Host, _Entity,
|
||||
{'open' = _Access_Model, _Affiliation, _Subscriptions, _Node_Owners,
|
||||
_Rosters_Groups_Allowed}) ->
|
||||
ok;
|
||||
%%
|
||||
check_access_model(Host, Entity,
|
||||
{'presence' = _Access_Model, _Affiliation, _Subscriptions, Node_Owners,
|
||||
_Rosters_Groups_Allowed}) ->
|
||||
case is_contact_subscribed_to_node_owners(Host, Entity, Node_Owners) of
|
||||
false ->
|
||||
{error, 'forbidden'};
|
||||
_Node_Owner ->
|
||||
ok
|
||||
end;
|
||||
%%
|
||||
check_access_model(_Host, Entity,
|
||||
{'roster' = _Access_Model, _Affiliation, _Subscriptions, _Node_Owners,
|
||||
Rosters_Groups_Allowed}) ->
|
||||
case is_contact_in_allowed_roster_groups(Entity, Rosters_Groups_Allowed) of
|
||||
false ->
|
||||
{error, 'forbidden'};
|
||||
{_Node_Owner, _Roster_Group_Allowed} ->
|
||||
ok
|
||||
end;
|
||||
%%
|
||||
check_access_model(_Host, _Entity,
|
||||
{'whitelist' = _Access_Model, Affiliation, _Subscriptions, _Node_Owners,
|
||||
_Roster_Groups_Allowed})
|
||||
when Affiliation == 'member'
|
||||
%%orelse Affiliation == 'owner'
|
||||
orelse Affiliation == 'publish-only'
|
||||
orelse Affiliation == 'publisher' ->
|
||||
ok;
|
||||
check_access_model(_Host, _Entity,
|
||||
{'whitelist' = _Access_Model, _Affiliation, _Subscriptions, _Node_Owners,
|
||||
_Roster_Groups_Allowed}) ->
|
||||
{error, 'forbidden'};
|
||||
%%
|
||||
check_access_model(_Host, _Entity,
|
||||
{'authorize' = _Access_Model, _Affiliation, Subscriptions, _Node_Owners,
|
||||
_Roster_Groups_Allowed}) ->
|
||||
case has_subscriptions(Subscriptions) of
|
||||
true -> ok;
|
||||
false -> {error, 'forbidden'}
|
||||
end.
|
||||
|
||||
|
||||
|
||||
%%
|
||||
-spec(check_access_model/7 ::
|
||||
(
|
||||
Host :: xmpp_jid:raw_jid_component_bare(),
|
||||
Entity :: xmpp_jid:usr_entity(),
|
||||
Access_Model :: pubsub_options:access_model(),
|
||||
Affiliation :: exmpp_pubsub:affiliation(),
|
||||
Subscriptions :: exmpp_pubsub:subscriptions(),
|
||||
Node_Owners :: [Node_Owner::xmpp_jid:usr_bare(),...],
|
||||
Rosters_Groups_Allowed :: pubsub_options:rosters_groups_allowed())
|
||||
-> ok
|
||||
%%%
|
||||
| {error, 'forbidden'}
|
||||
| {error, 'item-not-found'}
|
||||
).
|
||||
|
||||
check_access_model(_Host, _Entity, _Access_Model, 'owner' = _Affiliation,
|
||||
_Subscriptions, _Node_Owners, _Rosters_Groups_Allowed) ->
|
||||
ok;
|
||||
%%
|
||||
check_access_model(Host, Entity, Access_Model, 'outcast' = _Affiliation,
|
||||
_Subscriptions, Node_Owners, Rosters_Groups_Allowed) ->
|
||||
case Access_Model of
|
||||
%%
|
||||
'open'->
|
||||
{error, 'forbidden'};
|
||||
%%
|
||||
'presence' ->
|
||||
case
|
||||
is_contact_subscribed_to_node_owners(Host, Entity, Node_Owners)
|
||||
of
|
||||
false ->
|
||||
{error, 'item-not-found'};
|
||||
_Node_Owner ->
|
||||
{error, 'forbidden'}
|
||||
end;
|
||||
%%
|
||||
'roster' ->
|
||||
case
|
||||
is_contact_in_allowed_roster_groups(Entity,
|
||||
Rosters_Groups_Allowed)
|
||||
of
|
||||
false ->
|
||||
{error, 'item-not-found'};
|
||||
{_Node_Owner, _Roster_Group_Allowed} ->
|
||||
{error, 'forbidden'}
|
||||
end;
|
||||
%%
|
||||
'authorize' ->
|
||||
{error, 'forbidden'};
|
||||
%%
|
||||
'whitelist' ->
|
||||
{error, 'item-not-found'}
|
||||
end;
|
||||
%%
|
||||
check_access_model(_Host, _Entity, 'open' = _Access_Model, _Affiliation,
|
||||
_Subscriptions, _Node_Owners, _Rosters_Groups_Allowed) ->
|
||||
ok;
|
||||
%%
|
||||
check_access_model(Host, Entity, 'presence' = _Access_Model, _Affiliation,
|
||||
_Subscriptions, Node_Owners, _Rosters_Groups_Allowed) ->
|
||||
case is_contact_subscribed_to_node_owners(Host, Entity, Node_Owners) of
|
||||
false ->
|
||||
{error, 'item-not-found'};
|
||||
_Node_Owner ->
|
||||
ok
|
||||
end;
|
||||
%%
|
||||
check_access_model(_Host, Entity, 'roster' = _Access_Model, _Affiliation,
|
||||
_Subscriptions, _Node_Owners, Rosters_Groups_Allowed) ->
|
||||
case is_contact_in_allowed_roster_groups(Entity, Rosters_Groups_Allowed) of
|
||||
false ->
|
||||
{error, 'item-not-found'};
|
||||
{_Node_Owner, _Roster_Group_Allowed} ->
|
||||
ok
|
||||
end;
|
||||
%%
|
||||
check_access_model(_Host, _Entity, 'whitelist' = _Access_Model, Affiliation,
|
||||
_Subscriptions, _Node_Owners, _Roster_Groups_Allowed) ->
|
||||
case Affiliation of
|
||||
Affiliation
|
||||
when Affiliation == 'member'
|
||||
orelse Affiliation == 'publish-only'
|
||||
orelse Affiliation == 'publisher' ->
|
||||
ok;
|
||||
_Affiliation ->
|
||||
{error, 'item-not-found'}
|
||||
end;
|
||||
%%
|
||||
check_access_model(_Host, _Entity, 'authorize' = _Access_Model, _Affiliation,
|
||||
Subscriptions, _Node_Owners, _Roster_Groups_Allowed) ->
|
||||
case has_subscriptions(Subscriptions) of
|
||||
true ->
|
||||
ok;
|
||||
false ->
|
||||
{error, 'item-not-found'}
|
||||
end.
|
||||
|
||||
|
||||
-spec(check_publish_model/3 ::
|
||||
(
|
||||
Publish_Model :: pubsub_options:publish_model(),
|
||||
Affiliation :: exmpp_pubsub:affiliation(),
|
||||
Subscriptions :: exmpp_pubsub:subscriptions())
|
||||
-> ok
|
||||
%%%
|
||||
| {error, 'forbidden'}
|
||||
).
|
||||
|
||||
check_publish_model('open' = _Publish_Model, _Affiliation, _Subscriptions) ->
|
||||
ok;
|
||||
%%
|
||||
check_publish_model('publishers' = _Publish_Model, Affiliation, _Subscriptions) ->
|
||||
case Affiliation of
|
||||
Affiliation
|
||||
when Affiliation == 'owner'
|
||||
orelse Affiliation == 'publish-only'
|
||||
orelse Affiliation == 'publisher' ->
|
||||
ok;
|
||||
_Affiliation ->
|
||||
{error, 'forbidden'}
|
||||
end;
|
||||
%%
|
||||
check_publish_model('subscribers' = _Publish_Model, Affiliation, Subscriptions) ->
|
||||
case Affiliation of
|
||||
'owner' ->
|
||||
ok;
|
||||
_Affiliation ->
|
||||
case has_subscriptions(Subscriptions) of
|
||||
true ->
|
||||
ok;
|
||||
false ->
|
||||
{error, 'forbidden'}
|
||||
end
|
||||
end.
|
||||
|
||||
%%
|
||||
-spec(has_subscriptions/1 ::
|
||||
(
|
||||
Subscriptions :: exmpp_pubsub:subscriptions())
|
||||
-> Has_Subscriptions::boolean()
|
||||
).
|
||||
|
||||
has_subscriptions([] = _Subscriptions) ->
|
||||
false;
|
||||
has_subscriptions(
|
||||
[{'pending' = _Subscription_State, _SubId, _Resource, _Subscription_Options}]) ->
|
||||
false;
|
||||
has_subscriptions(_Subscriptions) ->
|
||||
true.
|
||||
|
||||
%%
|
||||
%% @doc Check if a contact is subscribed to at least one local node owner
|
||||
%% amongst a list of (remote and local) node owners
|
||||
-spec(is_contact_subscribed_to_node_owners/3 ::
|
||||
(
|
||||
Host :: xmpp_jid:raw_jid_component_bare(),
|
||||
Contact :: xmpp_jid:usr_entity(),
|
||||
Node_Owners :: [] | [Node_Owner::xmpp_jid:usr_bare(),...])
|
||||
-> Is_Contact_Subscribed_To_Node_Owners :: false | xmpp_jid:usr_bare()
|
||||
).
|
||||
|
||||
is_contact_subscribed_to_node_owners(_Host, _Contact, [] = _Node_Owners) ->
|
||||
false;
|
||||
%% The node owner is a local entity, check if the contact is subscribed to it
|
||||
is_contact_subscribed_to_node_owners(Host, Contact,
|
||||
[{_U, Host, _R} = Local_Node_Owner | Node_Owners] = _Node_Owners) ->
|
||||
_Is_Contact_Subscribed_To_Node_Owners = case
|
||||
is_contact_subscribed_to_entity(Contact,
|
||||
_Local_Node_Owner_Roster = get_entity_roster(Local_Node_Owner))
|
||||
of
|
||||
true ->
|
||||
Local_Node_Owner;
|
||||
false ->
|
||||
is_contact_subscribed_to_node_owners(Host, Contact, Node_Owners)
|
||||
end;
|
||||
%% The node owner is a remote entity, don't check if the contact is subscribed to it
|
||||
is_contact_subscribed_to_node_owners(Host, Contact,
|
||||
[_Remote_Node_Owner | Node_Owners] = _Node_Owners) ->
|
||||
is_contact_subscribed_to_node_owners(Host, Contact, Node_Owners).
|
||||
|
||||
%%
|
||||
%% @doc Check if an entity is in a #roster{}
|
||||
%% with #roster.subscription == 'from' or
|
||||
%% with #roster.subscription == 'both'
|
||||
-spec(is_contact_subscribed_to_entity/2 ::
|
||||
(
|
||||
Contact :: xmpp_jid:usr_entity(),
|
||||
Entity_Roster :: [] | [Roster_Item::#roster{},...])
|
||||
-> Is_Contact_Subscribed::boolean()
|
||||
).
|
||||
|
||||
is_contact_subscribed_to_entity(_Contact, [] = _Entity_Roster) ->
|
||||
_Is_Contact_Subscribed = false;
|
||||
%% Contact is included in a #roster{} item with
|
||||
%% a subscription of type 'from' and 'both' (i.e. is subscribed to it)
|
||||
is_contact_subscribed_to_entity({U, S, _R} = _Contact,
|
||||
[#roster{jid = {U, S, _}, subscription = Subscription} = _Roster_Item
|
||||
| _Roster_Items] = _Entity_Roster)
|
||||
when Subscription == 'from' orelse Subscription == 'both' ->
|
||||
_Is_Contact_Subscribed = true;
|
||||
%% Contact is not included in a #roster{} item
|
||||
%% or has a subscription of type different than 'from' and 'both'
|
||||
%% ( i.e. is not subscribed to it),
|
||||
%% check next roster items
|
||||
is_contact_subscribed_to_entity(Contact,
|
||||
[_Roster_Item | Roster_Items] = _Entity_Roster) ->
|
||||
_Is_Contact_Subscribed = is_contact_subscribed_to_entity(Contact,
|
||||
Roster_Items).
|
||||
|
||||
%%
|
||||
-spec(is_contact_in_allowed_roster_groups/2 ::
|
||||
(
|
||||
Contact :: xmpp_jid:usr_entity(),
|
||||
Rosters_Groups_Allowed :: pubsub_options:rosters_groups_allowed())
|
||||
-> Roster_Group_Allowed :: false
|
||||
| {Entity :: xmpp_jid:usr_bare(),
|
||||
Roster_Group :: pubsub_options:roster_group()}
|
||||
).
|
||||
|
||||
is_contact_in_allowed_roster_groups(_Contact, [] = _Rosters_Groups_Allowed) ->
|
||||
false;
|
||||
%%
|
||||
is_contact_in_allowed_roster_groups(Contact,
|
||||
[{Entity, Entity_Roster_Groups_Allowed} | Rosters_Groups_Allowed]
|
||||
= _Rosters_Groups_Allowed) ->
|
||||
case
|
||||
is_contact_in_allowed_roster_group(Contact,
|
||||
_Entity_Roster = get_entity_roster(Entity),
|
||||
Entity_Roster_Groups_Allowed)
|
||||
of
|
||||
false ->
|
||||
is_contact_in_allowed_roster_groups(Contact, Rosters_Groups_Allowed);
|
||||
Roster_Group ->
|
||||
{Entity, Roster_Group}
|
||||
end.
|
||||
|
||||
%%
|
||||
-spec(is_contact_in_allowed_roster_group/3 ::
|
||||
(
|
||||
Contact :: xmpp_jid:usr_entity(),
|
||||
Entity_Roster :: [] | [Roster_Item::#roster{groups::pubsub_options:roster_groups()}],
|
||||
Roster_Groups_Allowed :: [Roster_Group_Allowed::pubsub_options:roster_group(),...])
|
||||
-> Roster_Group :: false | pubsub_options:roster_group()
|
||||
).
|
||||
|
||||
is_contact_in_allowed_roster_group(_Contact, [] = _Entity_Roster,
|
||||
_Roster_Groups_Allowed) ->
|
||||
false;
|
||||
%%
|
||||
is_contact_in_allowed_roster_group({U, S, _R} = _Contact,
|
||||
[#roster{jid = {U, S, _}, subscription = Subscription, groups = Roster_Groups}
|
||||
| _Other_Roster_Items] = _Entity_Roster, Roster_Groups_Allowed)
|
||||
when Subscription == 'from' orelse Subscription == 'both' ->
|
||||
is_contact_in_allowed_roster_group(Roster_Groups, Roster_Groups_Allowed);
|
||||
%%
|
||||
is_contact_in_allowed_roster_group(Contact,
|
||||
[_Roster_Item | Roster_Items] = _Entity_Roster, Roster_Groups_Allowed) ->
|
||||
is_contact_in_allowed_roster_group(Contact, Roster_Items,
|
||||
Roster_Groups_Allowed).
|
||||
|
||||
%%
|
||||
-spec(is_contact_in_allowed_roster_group/2 ::
|
||||
(
|
||||
Roster_Groups :: [] | [Roster_Group::pubsub_options:roster_group()],
|
||||
Roster_Groups_Allowed :: [Roster_Group_Allowed::pubsub_options:roster_group(),...])
|
||||
-> Roster_Group :: false | pubsub_options:roster_group()
|
||||
).
|
||||
|
||||
is_contact_in_allowed_roster_group([] = _Roster_Groups, _Roster_Groups_Allowed) ->
|
||||
false;
|
||||
%%
|
||||
is_contact_in_allowed_roster_group([Roster_Group | Roster_Groups]
|
||||
= _Roster_Groups, Roster_Groups_Allowed) ->
|
||||
case lists:member(Roster_Group, Roster_Groups_Allowed) of
|
||||
true ->
|
||||
Roster_Group;
|
||||
false ->
|
||||
is_contact_in_allowed_roster_group(Roster_Groups,
|
||||
Roster_Groups_Allowed)
|
||||
end.
|
||||
|
||||
%%
|
||||
-spec(get_user_resources/2 ::
|
||||
(
|
||||
User :: binary(),
|
||||
Server :: binary())
|
||||
-> Resources::[Resource::xmpp_jid:resource_jid()]
|
||||
).
|
||||
|
||||
get_user_resources(User, Server) ->
|
||||
ejabberd_sm:get_user_resources(User, Server).
|
||||
|
||||
%%
|
||||
-spec(get_resources_show/2 ::
|
||||
(
|
||||
User :: binary(),
|
||||
Server :: binary())
|
||||
-> Resources_Show :: [{Resource :: xmpp_jid:resource_jid(),
|
||||
Show :: 'away' | 'chat' | 'dnd' | 'online' | 'xa' }]
|
||||
).
|
||||
|
||||
get_resources_show(User, Server) ->
|
||||
_Resources_Show = lists:foldl(fun
|
||||
(Resource, Resources_Show) ->
|
||||
case ejabberd_sm:get_session_pid(User, Server, Resource) of
|
||||
C2SPid when is_pid(C2SPid) ->
|
||||
case ejabberd_c2s:get_presence(C2SPid) of
|
||||
{_User, _Resource, Show, _} ->
|
||||
[{Resource, list_to_atom(Show)} | Resources_Show];
|
||||
_ ->
|
||||
Resources_Show
|
||||
end;
|
||||
_ ->
|
||||
Resources_Show
|
||||
end
|
||||
end, [], _Resources = ejabberd_sm:get_user_resources(User, Server)).
|
||||
|
||||
|
||||
%%
|
||||
-spec(rosters_groups_allowed_cache/2 ::
|
||||
(
|
||||
Rosters_Groups_Allowed :: pubsub_options:rosters_groups_allowed(),
|
||||
Rosters_Groups_Allowed_Cache :: pubsub_options:rosters_groups_allowed())
|
||||
-> Is_Roster_Groups_Cached::boolean()
|
||||
).
|
||||
|
||||
rosters_groups_allowed_cache(_Rosters_Groups_Allowed,
|
||||
[] = _Rosters_Groups_Allowed_Cache) ->
|
||||
false;
|
||||
%%
|
||||
rosters_groups_allowed_cache([] = _Rosters_Groups_Allowed,
|
||||
_Rosters_Groups_Allowed_Cache) ->
|
||||
false;
|
||||
%%
|
||||
rosters_groups_allowed_cache(
|
||||
[{Entity, Roster_Groups_Allowed} | Rosters_Groups_Allowed],
|
||||
Rosters_Groups_Allowed_Cache) ->
|
||||
case lists:keyfind(Entity, 1, Rosters_Groups_Allowed_Cache) of
|
||||
{_Entity, Roster_Groups_Allowed_Cache} ->
|
||||
case
|
||||
roster_groups_allowed_cache(Roster_Groups_Allowed,
|
||||
Roster_Groups_Allowed_Cache)
|
||||
of
|
||||
true ->
|
||||
true;
|
||||
false ->
|
||||
rosters_groups_allowed_cache(Rosters_Groups_Allowed,
|
||||
Rosters_Groups_Allowed_Cache)
|
||||
end;
|
||||
false ->
|
||||
rosters_groups_allowed_cache(Rosters_Groups_Allowed,
|
||||
Rosters_Groups_Allowed_Cache)
|
||||
end.
|
||||
|
||||
%%
|
||||
-spec(roster_groups_allowed_cache/2 ::
|
||||
(
|
||||
Roster_Groups_Allowed :: [Roster_Group_Allowed::pubsub_options:roster_group()],
|
||||
Roster_Groups_Allowed_Cache :: [Roster_Group_Allowed_Cache::pubsub_options:roster_group()])
|
||||
-> Is_Roster_Groups_Cached :: boolean()
|
||||
).
|
||||
|
||||
roster_groups_allowed_cache(_Roster_Groups_Allowed,
|
||||
[] = _Roster_Groups_Allowed_Cache) ->
|
||||
false;
|
||||
%%
|
||||
roster_groups_allowed_cache([] = _Roster_Groups_Allowed,
|
||||
_Roster_Groups_Allowed_Cache) ->
|
||||
false;
|
||||
%%
|
||||
roster_groups_allowed_cache([Roster_Group_Allowed | Roster_Groups_Allowed],
|
||||
Roster_Groups_Allowed_Cache) ->
|
||||
case lists:member(Roster_Group_Allowed, Roster_Groups_Allowed_Cache) of
|
||||
true ->
|
||||
true;
|
||||
false ->
|
||||
roster_groups_allowed_cache(Roster_Groups_Allowed,
|
||||
Roster_Groups_Allowed_Cache)
|
||||
end.
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
-module(xmpp_xdata).
|
||||
|
||||
|
||||
-include("jlib.hrl").
|
||||
-include("ejabberd.hrl").
|
||||
-compile(export_all).
|
||||
|
||||
xmlcdata(CData) ->
|
||||
{xmlcdata, CData}.
|
||||
|
||||
xmlattr(Name, Value) ->
|
||||
% #xmlattr{name = Name, value = Value}.
|
||||
{Name, Value}.
|
||||
|
||||
xmlattr_label(Label) ->
|
||||
xmlattr(<<"label">>, Label).
|
||||
|
||||
xmlattr_type(Type) ->
|
||||
xmlattr(<<"type">>, Type).
|
||||
|
||||
xmlattr_var(Var) ->
|
||||
xmlattr(<<"var">>, Var).
|
||||
|
||||
|
||||
xmlel(NS, Name, Attrs, Children) ->
|
||||
#xmlel{name = Name, attrs = [{<<"xmlns">>, NS} | Attrs], children = Children}.
|
||||
|
||||
xmlel(Name, Attrs, Children) ->
|
||||
xmlel(?NS_XDATA, Name, Attrs, Children).
|
||||
|
||||
xmlel_desc(CData) ->
|
||||
xmlel(<<"desc">>, [], [xmlcdata(CData)]).
|
||||
|
||||
xmlel_value(Value) ->
|
||||
xmlel(<<"value">>, [], [xmlcdata(Value)]).
|
||||
|
||||
xmlel_option({Value, Label}) ->
|
||||
xmlel(<<"option">>, [xmlattr_label(Label)], [xmlel_value(Value)]);
|
||||
xmlel_option(Value) ->
|
||||
xmlel(<<"option">>, [], [xmlel_value(Value)]).
|
||||
|
||||
xmlel_field(Var, Type, Values) ->
|
||||
xmlel(<<"field">>,
|
||||
[xmlattr_var(Var),
|
||||
xmlattr_type(Type)],
|
||||
[xmlel_value(Value) || Value <- Values]).
|
||||
|
||||
xmlel_field(Var, Type, Label, Values, Options) ->
|
||||
xmlel(<<"field">>,
|
||||
[xmlattr_var(Var),
|
||||
xmlattr_label(Label),
|
||||
xmlattr_type(Type)],
|
||||
[xmlel_option(Option) || Option <- Options]
|
||||
++
|
||||
[xmlel_value(Value) || Value <- Values]).
|
||||
|
||||
xmlel_field_boolean(Var, Label, Value) ->
|
||||
xmlel_field(Var, <<"boolean">>, Label, [Value], []).
|
||||
|
||||
%%
|
||||
xmlel_field_fixed(Var, Label, Value) ->
|
||||
xmlel_field(Var, <<"fixed">>, Label, [Value], []).
|
||||
|
||||
%%
|
||||
xmlel_field_hidden(Var, Value) ->
|
||||
xmlel_field(Var, <<"hidden">>, [Value]).
|
||||
|
||||
%%
|
||||
xmlel_field_list_single(Var, Label, Value, Options) ->
|
||||
xmlel_field(Var, <<"list-single">>, Label, [Value], Options).
|
||||
|
||||
%%
|
||||
xmlel_field_list_multi(Var, Label, Values, Options) ->
|
||||
xmlel_field(Var, <<"list-multi">>, Label, Values, Options).
|
||||
|
||||
%%
|
||||
xmlel_field_text_single(Var, Label, undefined = _Text) ->
|
||||
xmlel_field(Var, <<"text-single">>, Label, [], []);
|
||||
%%
|
||||
xmlel_field_text_single(Var, Label, Text) ->
|
||||
xmlel_field(Var, <<"text-single">>, Label, [Text], []).
|
||||
|
||||
%%
|
||||
xmlel_field_text_multi(Var, Label, Values) ->
|
||||
xmlel_field(Var, <<"text-multi">>, Label, Values, []).
|
||||
|
||||
%%
|
||||
xmlel_field_jid_multi(Var, Label, Jids) ->
|
||||
xmlel_field(Var, <<"jid-multi">>, Label, Jids, []).
|
||||
|
||||
%%
|
||||
xmlel_field_jid_single(Var, Label, Jid) ->
|
||||
xmlel_field(Var, <<"jid-single">>, Label, [Jid], []).
|
||||
|
||||
%%
|
||||
xmlel_x(Type, Fields) ->
|
||||
xmlel(<<"x">>, [xmlattr_type(Type)], Fields).
|
||||
|
||||
%%
|
||||
xmlel_title(Title) ->
|
||||
xmlel(<<"title">>, [], [xmlcdata(Title)]).
|
||||
|
||||
%%
|
||||
xmlel_instructions(Instructions) when is_list(Instructions) ->
|
||||
lists:map(fun xmlel_instructions/1, Instructions);
|
||||
%%
|
||||
xmlel_instructions(Instruction) when is_binary(Instruction) ->
|
||||
xmlel(<<"instructions">>, [], [xmlcdata(Instruction)]).
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user