Compare commits

...

461 Commits

Author SHA1 Message Date
Evgeniy Khramtsov e4ec23919d Merge branch 'rebar' into 3.0.x 2013-05-28 00:12:00 +10:00
Evgeniy Khramtsov 1c095b609a Merge branch '3.0.x' of github.com:processone/maincustomers into 3.0.x 2013-05-15 21:58:14 +10:00
Evgeniy Khramtsov a819514e43 Define primary key in sr_group table 2013-05-15 21:57:53 +10:00
Evgeniy Khramtsov 16cd93d587 Improve applications startup 2013-05-15 18:46:56 +10:00
Evgeniy Khramtsov a8e5984f5f Reflect applications name change 2013-05-15 17:33:49 +10:00
Evgeniy Khramtsov 1a45637860 Improve the profiler 2013-05-15 16:34:02 +10:00
Badlop 8cb3f61f88 Tweak ejabberd_listener to allow ejabberd_xmlrpc work properly 2013-05-14 18:50:29 +02:00
Evgeniy Khramtsov 4bc4f54e43 Do not make DB query on get_group_opt (part of TECH-220) 2013-05-14 17:31:24 +10:00
Evgeniy Khramtsov 08774b1b5a Pass --enable-flash-hack flag to "xml" app 2013-05-13 15:55:46 +10:00
Evgeniy Khramtsov 300e765e20 Call all logging functions via single module 2013-05-12 19:41:59 +10:00
Evgeniy Khramtsov 951599be21 Describe the new configure options in the guide 2013-05-12 16:05:41 +10:00
Evgeniy Khramtsov 8bea14837e Do not forget to remove autom4te.cache on distclean 2013-05-12 14:40:26 +10:00
Evgeniy Khramtsov 09250d6121 Do not allow underscores in configure options 2013-05-12 14:37:57 +10:00
Evgeniy Khramtsov 5968b35320 Make it possible to combine --enable-all
with other configure options
2013-05-12 14:30:49 +10:00
Evgeniy Khramtsov f364fcda56 Add --enable-tools configure option 2013-05-12 14:13:16 +10:00
Evgeniy Khramtsov 170874e115 Fix PubSub NG compilation 2013-05-11 20:53:51 +10:00
Evgeniy Khramtsov bec499a4a1 Check if all needed Erlang applications are installed 2013-05-11 15:46:01 +10:00
Evgeniy Khramtsov d6709bd53a Fix --enable-pubsub_ng configuration option 2013-05-09 21:22:27 +10:00
Evgeniy Khramtsov 1cd1dd9f23 Use another XML-RPC library 2013-05-09 20:57:27 +10:00
Evgeniy Khramtsov af198dbe92 Change {{localstatedir}} overlay variable 2013-05-09 19:30:03 +10:00
Evgeniy Khramtsov 80ff4ad3d3 Rename config.vars to vars.config 2013-05-09 19:05:35 +10:00
Evgeniy Khramtsov 6e1691e2fa Do not set ERLANG_ROOT_DIR and ERLANG_LIB_DIR variable 2013-05-09 19:00:25 +10:00
Evgeniy Khramtsov e52c324a5e Exclude riak_pb from the PLT 2013-05-09 17:58:29 +10:00
Evgeniy Khramtsov e7b1f21e1c Add syntax_tools to the PLT list 2013-05-09 17:03:47 +10:00
Evgeniy Khramtsov a2d2581199 Do not dump dynamic configuration 2013-05-09 11:56:01 +10:00
Evgeniy Khramtsov eedd9496e4 Add --enable-all compiler option 2013-05-09 11:30:10 +10:00
Evgeniy Khramtsov 3d4775d555 Update dialyzer target 2013-05-09 01:14:58 +10:00
Evgeniy Khramtsov 7f11f4a1fb Do not cd when generating a release 2013-05-08 23:59:58 +10:00
Evgeniy Khramtsov 612f15ab17 Do not dump the release file 2013-05-08 23:51:56 +10:00
Evgeniy Khramtsov af9ff6f1a1 Fix logging 2013-05-08 23:51:21 +10:00
Evgeniy Khramtsov 9664de5242 Properly create log directory 2013-05-08 23:11:17 +10:00
Evgeniy Khramtsov b13c51c8cf Better release directory detection 2013-05-08 22:52:10 +10:00
Evgeniy Khramtsov 8229ee8dd8 Make it possible to generate an OTP application release 2013-05-08 21:56:29 +10:00
Evgeniy Khramtsov 476acbfa44 Move configure variables to a separate file 2013-05-08 19:27:25 +10:00
Evgeniy Khramtsov 23dd81d18c Move cache_tab code to deps 2013-05-08 15:17:11 +10:00
Evgeniy Khramtsov f08595b0e5 Get rid of stub rebar.config 2013-05-08 14:48:52 +10:00
Evgeniy Khramtsov 50b8500bd5 Run the corresponding configure scripts by ourselves 2013-05-08 13:32:18 +10:00
Christophe Romain 1cacd48261 add simple event logger 2013-05-07 10:42:50 +02:00
Evgeniy Khramtsov cf11acc450 Add stub Rebar config 2013-05-07 17:56:35 +10:00
Evgeniy Khramtsov 0c18dd7068 Improve "install" target 2013-05-07 17:23:34 +10:00
Badlop 4e807d69e8 Fix paths for "install" target 2013-05-06 12:52:26 +02:00
Paweł Chmielowski a61b7b1d98 Don't forget about directed presences sent after receiving global presence
It caused problem with presences send to conference rooms, as this change
made us not always send presence unavailable when user went offline, which
did make conference have phantom users.

This revert functional changes introduced in
e521c8368a
2013-05-03 10:42:24 +02:00
Paweł Chmielowski a55c85252f Add ability to limit number of registered users.
This limit can be configure in host_config options like this:

{host_config "jabber.example.org", [{max_users, 100}]}.
2013-05-03 10:33:19 +02:00
Evgeniy Khramtsov 0168e39bb3 Use xml repo 2013-05-02 21:04:55 +10:00
Evgeniy Khramtsov 8f8b6870a0 Fix a typo 2013-05-02 20:36:45 +10:00
Evgeniy Khramtsov dc7208ed1c Only compile ibrowse and lhttpc when needed 2013-05-02 20:36:10 +10:00
Evgeniy Khramtsov 60b0b918a6 Dump the resulting Rebar configuration 2013-05-02 20:27:53 +10:00
Evgeniy Khramtsov d9e2d4e6a9 Get rid of useless makefiles 2013-05-02 20:17:58 +10:00
Evgeniy Khramtsov 8fc80178b6 Fix STUN startup 2013-05-02 20:00:04 +10:00
Evgeniy Khramtsov c801bd9411 Do not try to start STUN supervisor 2013-05-02 19:31:59 +10:00
Evgeniy Khramtsov b9d5a3350d Better rebar detection 2013-05-02 19:02:40 +10:00
Evgeniy Khramtsov 2bb0095a32 Add install target (not working so far) 2013-05-02 18:41:51 +10:00
Evgeniy Khramtsov eda360914e Add --enable-pubsub_ng option 2013-05-02 18:29:40 +10:00
Evgeniy Khramtsov 042172eae1 Disable transient_supervisors compile option as
it is not needed anymore in the newer Erlang versions
2013-05-02 18:17:05 +10:00
Evgeniy Khramtsov 0eaab78f67 Add --enable-debug compile option 2013-05-02 18:15:03 +10:00
Evgeniy Khramtsov 5ec65571f8 Update README file 2013-05-01 23:36:16 +10:00
Evgeniy Khramtsov 7bbc98b04c Make iconv dependency optional 2013-05-01 23:35:01 +10:00
Evgeniy Khramtsov eda6b80ece Use dynamic Rebar configuration 2013-05-01 23:22:26 +10:00
Evgeniy Khramtsov 2ddb7be19a Replace stand-alone Rebar script with the new one 2013-05-01 21:35:57 +10:00
Evgeniy Khramtsov 04f20a21fb Improve build procedure 2013-05-01 21:02:29 +10:00
Evgeniy Khramtsov 40ae9b33ef Add a function for massive users creation 2013-04-29 21:05:10 +10:00
Evgeniy Khramtsov e2357ecd96 Add a function for massive roster creation 2013-04-29 20:52:55 +10:00
Paweł Chmielowski 0116287405 Properly convert responses from ODBC databases, when generating command results 2013-04-26 17:48:18 +02:00
Christophe Romain 6ee534b262 return success on command on updated records as well 2013-04-26 01:23:40 +02:00
Paweł Chmielowski 42f72a49b1 When ej_command don't have example input, try to generate one based on args type 2013-04-22 12:45:15 +02:00
Evgeniy Khramtsov 771acc3ac7 Set utf8_bin collation for MySQL (thanks to George Hazan) 2013-04-17 23:51:55 +10:00
Paweł Chmielowski 5706aaa89c Add XMLRPC documentation generator for ejabberd_commands
This functionality is available as additional ejabberd_command, executing
'ejabberdctl gen_xmlrpc_docs /home/me/docs/out.html shared_roster' will
generate html file with description of all commands which names match
regexp shared_roster.

To get better output #ejabberd_command definitions get extended with few
new fields, now it's possible to specify description for each
argument (in args_desc field), result (result_desc) and provide example
arguments list (args_example) or result (result_example) used to generate
example code in various languages.

All those fields are optional, so output for not updated commands still
will be generated, but will not look as good.
2013-04-16 11:35:47 +02:00
Alexey Shchepin c17bbc8859 Use get_roster hook instead of mod_roster:get_user_roster in mod_admin_p1 2013-04-11 14:00:37 +03:00
Alexey Shchepin 8f317c0059 Fixed mod_shared_roster:add_user_to_group return value, which was broken after the previous change 2013-04-10 15:38:43 +03:00
Evgeniy Khramtsov d1c654a7e1 Initiate new directory structure and moved some code in deps 2013-04-08 19:12:54 +10:00
Alexey Shchepin ae5c31b06d Fixed shared roster updates pushing 2013-04-07 21:22:35 +03:00
Alexey Shchepin b09cda5c17 ejabberd_ws is now R16B-compatible 2013-04-03 15:14:16 +03:00
Christophe Romain 7887392c1d Update copyright dates 2013-03-27 10:36:48 +01:00
Paweł Chmielowski cc2b7d2832 Fix argument types in user_resources command 2013-03-22 13:47:05 +01:00
Paweł Chmielowski 0a69935b6b Fix type arguments in commands from mod_admin_p1 2013-03-22 13:46:30 +01:00
Paweł Chmielowski 4b7c74415f Fix warning from last commit 2013-03-19 19:09:16 +01:00
Paweł Chmielowski 418baf4fa6 Fix processing of list arguments in xmlrpc handler
Before this change only lists with exactly single element were handled
properly.
2013-03-19 19:02:03 +01:00
Paweł Chmielowski fcf647738d erlang:integer_to_binary was added in R16, switch to method which works in older versions 2013-03-18 12:46:59 +01:00
Paweł Chmielowski 3c9ab9e53d Httpc is not able to process binary headers or url, we need to convert them 2013-03-18 12:44:26 +01:00
Paweł Chmielowski c339c9b2ad Add ejabberd_commands for managing shared roster groups 2013-03-13 12:14:05 +01:00
Paweł Chmielowski 4ef32bb18f Make ejabberd_ctl not die for ejabberd_commands with binary arguments 2013-03-13 11:13:19 +01:00
Paweł Chmielowski 0f87034539 Make http connections serve flash policy files 2013-02-01 13:05:20 +01:00
Paweł Chmielowski acee58f6bb Fix problem from conversion to binaries in old websocket protocol handler 2013-01-31 20:11:02 +01:00
Jerome Sautret ceeef24faa Fix type error on MUC room config form generation. 2013-01-30 11:05:38 +01:00
Badlop 201b0b3725 Fix another dialyzer warning 2013-01-09 22:25:54 +01:00
Badlop 5f8b41a357 ssl:seed was removed in OTP R14B04. Fix dialyzer warning. 2013-01-09 12:58:57 +01:00
Badlop a003ef556b Fix two dialyzer warnings 2013-01-09 12:40:42 +01:00
Badlop cb91e10803 Copied check_account and check_password from old mod_xmlrpc (TECH-1519) 2013-01-04 13:32:21 +01:00
Badlop 5190866a24 Copied set_rosternick from old mod_xmlrpc (TECH-1519) 2013-01-04 12:37:35 +01:00
Evgeniy Khramtsov 473a58e3c2 Fix iconv wrapper 2013-01-03 20:15:33 +10:00
Pablo Polvorin 3e6b88cbc3 Fix pubsub_state mnesia table definition
Partially bound lookups keys only works efficiently if the table
type if ordered_set.
If the table is a set, then it is implemented as a hashtable,
and if the lookup key isn't fully bound an entire table scan
is neccesarly.
2012-12-21 12:48:27 -03:00
Alexey Shchepin 362d7f617d Fixed signedness issue in tls_drv GET_DESCRYPTED_INPUT (EJAB-1591) 2012-12-20 14:03:28 +02:00
Remco Wendt d11df52abf Added command to list all the vhosts registered in an ejabberd node 2012-12-19 15:08:19 +02:00
Janusz Dziemidowicz 906161b27f Detect OpenSSL version at runtime, not at compile time 2012-12-17 14:41:37 +02:00
Janusz Dziemidowicz 347e8b28ef Enable DHE key exchange in TLS driver 2012-12-17 14:41:37 +02:00
Janusz Dziemidowicz c85c2796f4 Enable ECDHE key exchange in TSL driver 2012-12-17 14:41:37 +02:00
Janusz Dziemidowicz df72de96ae Disable old and unsecure ciphers in TLS driver
Disable:
- export ciphers - broken by design, 40 and 56 bit encryption
- low encryption ciphers - 56 and 64 bit encryption
- SSLv2 ciphers - some ciphers using MD5 MAC
2012-12-17 14:41:37 +02:00
Evgeniy Khramtsov e1f8233d08 Fix broken JPEG photo (EJAB-1526)
Conflicts:

	src/eldap/eldap_filter.erl
2012-12-12 18:10:08 +10:00
Badlop 38d2a27c56 Provide ejabberd_xmlrpc configuration examples 2012-12-10 13:56:16 +01:00
Badlop 6a42119292 Document ejabberd_xmlrpc in the Guide 2012-12-10 13:36:47 +01:00
Badlop 89787875d4 In frontends, if result is in binary then convert to string 2012-12-10 13:36:34 +01:00
Badlop d76ae701cd Partial revert "Test for binary arguments and results to get_roster command" 2012-12-10 13:35:37 +01:00
Evgeniy Khramtsov c4db156ad2 Reflect new ejabberd_sets usage in the type spec.
This will eliminate dialyzer warnings
2012-12-10 12:40:09 +10:00
Evgeniy Khramtsov d95778ea16 Make hash lookups more robust (EJABS-1965)
Conflicts:

	src/ejabberd_cluster.erl
2012-12-10 12:38:17 +10:00
Alexey Shchepin a9b452fba9 Fixed config parsing error messages 2012-12-07 16:12:49 +02:00
Alexey Shchepin afed9e919e Use ejabberd_listener instead of tcp_serv in ejabberd_xmlrpc 2012-12-07 16:06:15 +02:00
Badlop 5252dcbd2c Fix some http Dialyzer warnings 2012-12-07 13:53:58 +01:00
Evgeniy Khramtsov a5cfac76dd Don't bounce broadcasts, i.e. bounce xmlel{}s only 2012-11-29 14:28:28 +10:00
Badlop 45aa32f6fe Document export_odbc command 2012-11-26 14:01:25 +01:00
Evgeniy Khramtsov 2372e30150 Improve Riak support 2012-11-21 11:30:50 +10:00
Alexey Shchepin f3b55596b2 Updated riak support
Conflicts:

	src/mod_roster.erl
2012-11-21 11:30:30 +10:00
Alexey Shchepin 84eee8d5a7 Preliminary Riak support 2012-11-21 11:28:49 +10:00
Badlop a800a5d4df Test for binary arguments and results to get_roster command 2012-11-20 13:57:41 +01:00
Badlop dfa47556d1 Add support for binary arguments and results to ejabberd_xmlrpc 2012-11-20 13:57:41 +01:00
Badlop 77111aeec1 Add support for binary arguments to ejabberd_xmlrpc 2012-11-20 12:43:59 +01:00
Badlop c9ac75474f Update to xmlrpc-rds13
Cloned from
https://github.com/rds13/xmlrpc
2012-11-20 12:43:54 +01:00
Pablo Polvorin 0fcaef0566 Backward compatibility for xep-0280 v0.6 (EJABS-1953)
make mod_carboncopy supports v0.8 and v0.6
2012-11-19 16:05:23 -03:00
Badlop 031c7412a8 Partially revert "Fix and document persistent_history MUC option (EJABS-1865)"
This reverts commit ab9ac62138.
2012-11-19 13:28:57 +01:00
Evgeniy Khramtsov 594ff79514 Make terms serialization faster
Conflicts:

	src/odbc/ejabberd_odbc.erl
2012-11-18 12:30:36 +10:00
Evgeniy Khramtsov 8f3f74a6d7 Only migrate C2S processes with remote sockets
Conflicts:

	src/ejabberd_c2s.erl
	src/ejabberd_sm.erl
2012-11-16 20:36:40 +10:00
Evgeniy Khramtsov ff2050b301 Clean tables from remote pids when their node goes down
Conflicts:

	src/ejabberd_sm.erl
	src/mod_muc/mod_muc.erl
	src/web/mod_bosh.erl
2012-11-15 15:16:42 +10:00
Pablo Polvorin 89ea1dd1c4 Adapt to XEP-0280 v0.8 2012-11-14 12:57:25 -03:00
Pablo Polvorin 66902b788b Do not require special api for ejabberd_set
Remove the pack() function, make mod_roster
return subscriptions splitted by {From, To, Both}
2012-11-12 22:32:33 -03:00
Christophe Romain ec8cb81c0d make sure publisher is #jid (TECH-1499) 2012-11-12 16:08:09 +01:00
Pablo Polvorin 1a24ac62e5 Change representation of JID sets
Instead of a single set, use a map from domains to
resources (in presence sets the resource is usually empty) to
users.  This makes the sharing explicit

DomainA
	-> Resource1
		-> User1, User2, ..
	-> Resource2
		-> User3
DomainB
	->Resource3
		-> User4, User5, User6
2012-11-11 22:25:20 -03:00
Pablo Polvorin 78fb913a00 Use a custom set module, reuse structs when possible.
For JID sets in ejabberd_c2s
2012-11-09 21:53:28 -03:00
Pablo Polvorin e521c8368a Improvement
Instead of traversing and constructing a new set,
share the set structure when constructing the pres_a
set.
2012-11-09 16:58:47 -03:00
Pablo Polvorin ac8c536b50 Improvement
Force the binary to be a heap binary, rather than
keeping it as a refcount or sub-binary
2012-11-09 16:57:23 -03:00
Badlop 84d9ee07b4 Document MUC domain_balancing broadcast (EJABS-1866) 2012-11-06 10:54:58 +01:00
Badlop ab9ac62138 Fix and document persistent_history MUC option (EJABS-1865) 2012-11-02 13:21:50 +01:00
Evgeniy Khramtsov beaf351ba4 Document mod_admin_p1 module 2012-11-01 18:48:23 +10:00
Alexey Shchepin 37d3a4e1f5 Merge branch '3.0.x' of git+ssh://git@gitorious.process-one.net/+ejabberd-developers/ejabberd/maincustomers.git into 3.0.x 2012-10-30 14:18:32 +02:00
Alexey Shchepin 566c046cd5 Fixed "message" tag checking in standby mode 2012-10-30 14:17:49 +02:00
Badlop df921fef40 Show binaries as strings in WebAdmin; handle tab characters. 2012-10-30 13:05:30 +01:00
Alexey Shchepin 56e7affdfd Don't try to send privacy pushes in OOR mode (a line was not removed in the previous commit) 2012-10-30 13:45:04 +02:00
Alexey Shchepin bef66dba24 Don't try to send privacy pushes in OOR mode 2012-10-30 13:29:15 +02:00
Pablo Polvorin e62af41fa8 Fix mod_ack:user_send_packet/3 signature (thanks zzolkiewski)
That hook has 4 arguments
2012-10-29 12:25:44 -03:00
Badlop 472089a328 Show binaries in a pretty format in WebAdmin 2012-10-29 13:40:50 +01:00
Evgeniy Khramtsov c4d582ace4 Add the guide for commercial usage 2012-10-29 20:15:46 +10:00
Evgeniy Khramtsov a4e320c263 Get rid of dreaded tuple_to_list(now()) 2012-10-26 20:02:25 +10:00
Evgeniy Khramtsov 7d3d008940 Fix data convertion 2012-10-25 22:42:58 +10:00
Evgeniy Khramtsov 3be9c27509 "epam" should return binaries, not strings 2012-10-24 18:09:11 +10:00
Evgeniy Khramtsov 3ef6e4c834 Process 'max_s2s_connections' and 'max_s2s_connections_per_node'
options correctly
2012-10-23 21:16:05 +10:00
Alexey Shchepin a15e689386 Merge branch '3.0.x' of git+ssh://git@gitorious.process-one.net/+ejabberd-developers/ejabberd/maincustomers.git into 3.0.x 2012-10-03 16:22:32 +03:00
Alexey Shchepin 7c8a452b00 Fixed a typo in ejabberd_s2s_in SUPERVISOR_START definition 2012-10-03 16:21:54 +03:00
Christophe Romain e5d202a0bf clean the pubsub odbc patch 2012-10-01 11:48:08 +02:00
Evgeniy Khramtsov 083dfe01ea Check a node of a migrating process (EJABS-1908) 2012-09-27 12:39:52 +10:00
Christophe Romain f0c745b916 add OSX compatibility note 2012-09-26 09:55:30 +02:00
Badlop 9ff1a80db4 Fix record definition (EJAB-1578) 2012-09-18 17:50:53 +02:00
Evgeniy Khramtsov 5480ee29fd Fix spec 2012-09-18 23:39:40 +10:00
Evgeniy Khramtsov 0d4b0b4218 Fix dialyzer types 2012-09-18 23:30:28 +10:00
Paweł Chmielowski cfe396e155 Don't forget about webscoket_handlers in pipelined http requests 2012-09-14 18:34:58 +02:00
Paweł Chmielowski 2163cbb22e Make websocket work over tls 2012-09-14 18:29:16 +02:00
Paweł Chmielowski 6b3f228327 Unify paths for handling websocket and regular http requests
This allow to easily produce html output from error paths in websocket code,
and this ability is used to produce informational page when regular http
request is directed to websocket url. Additionally HEAD and OPTIONS request
are now handled correctly.
2012-09-14 17:51:54 +02:00
Paweł Chmielowski e58e6a09dd Unify GET and POST handling code
Code for both it almost identical, extract all differences to separate
function extract_path_query.
2012-09-14 17:11:35 +02:00
Paweł Chmielowski 2d05ddd466 Fix syntax error in ejabberd_websocket 2012-09-14 16:07:58 +02:00
Paweł Chmielowski 975f4c56d4 Don't try to decode utf-8 codepoints in ej_websocket only to convert it back to utf-8 in ej_http_ws
Additionally that conversion code was wrong sometimes and lead to loosing
some bits of information.

This fixes EJABS-1875
2012-09-14 10:20:33 +02:00
Paweł Chmielowski 8eef2f02bf Properly handle websocket sub-protocols 2012-09-14 10:15:32 +02:00
Paweł Chmielowski 2f7c69fd14 Properly handle close op in websocket 2012-09-14 10:05:42 +02:00
Pablo Polvorin 02eeebd41a Fix mod_ack, make it work with both oor and normal clients.
If the client is able to go to oor, mod_ack must made it do so.
If the client is not able to to go oor mode,  mod_ack must stop
the c2s session, and wait for it to really terminate before
continuing (to avoid race conditions, see EJABS-1677).

Conflicts:

	src/ejabberd_c2s.erl
	src/mod_ack.erl
	src/mod_ping.erl
2012-09-13 14:05:36 -03:00
Pablo Polvorin 99610c3357 Make mod_ack work with applepush (TECH-1463) (thanks aleksey)
Do not forcelly kill the c2s process.

Conflicts:

	src/mod_ack.erl

Conflicts:

	src/mod_ack.erl
2012-09-13 13:50:39 -03:00
Evgeniy Khramtsov aad740f34c LDAP StartTLS support
Conflicts:

	src/ejabberd_auth_ldap.erl
	src/eldap/eldap.erl
	src/mod_shared_roster_ldap.erl
	src/mod_vcard_ldap.erl
	src/tls/tls.erl
2012-09-13 17:59:45 +10:00
Evgeniy Khramtsov a70c72e50e Move SM dispatchers code in a separate file
and make it more robust (EJABS-1845)

Conflicts:

	src/ejabberd_sm.erl
	src/ejabberd_sup.erl
2012-09-13 17:09:32 +10:00
Evgeniy Khramtsov a2fdc75730 Add forgotten file 2012-09-13 17:04:23 +10:00
Evgeniy Khramtsov b82789f11d Make gen_iq_handlers more robust (EJABS-1758)
Conflicts:

	src/ejabberd_local.erl
	src/ejabberd_sm.erl
	src/gen_iq_handler.erl
2012-09-13 17:04:13 +10:00
Evgeniy Khramtsov 6b7d70adf6 Do not close session with an item-not-found error when
receiving duplicate request with same rid as the currently
active one (EJABS-1844) (thanks to Pawel Chmielowski)

Conflicts:

	src/web/ejabberd_bosh.erl
2012-09-13 16:50:54 +10:00
Badlop 10f10a2fd3 Allow multiple fqdn values in configuration (EJAB-1578) 2012-09-12 19:55:00 +02:00
Badlop 35c4e740ab Fix recent commit "Reduce size..." 2012-09-12 19:48:18 +02:00
Christophe Romain e3085a4d48 put cleaning code to pubsub_debug 2012-09-12 15:08:39 +02:00
Janusz Dziemidowicz e8d008c392 Reduce size of XML stream state
This makes size of hibernated ejabberd_receiver a lot smaller (from
~290 words down to ~40).
2012-09-11 21:27:16 +02:00
Badlop 674ab27700 Send announce Message stanzas as Headline type instead of Normal 2012-09-11 20:32:29 +02:00
Badlop 9442a583bc Check node name is available before starting ejabberd (EJAB-1572) 2012-09-11 20:22:56 +02:00
Badlop 9787416e88 Fix file name of Name Service Switch (thanks to Konstantin Khomoutov) 2012-09-11 19:38:38 +02:00
Badlop fbe2995696 Update Slovak translation (thanks to Marek Bečka) 2012-09-11 17:39:37 +02:00
Christophe Romain 33251cd5a8 fix configure to display generic version 2012-09-11 17:27:31 +02:00
Christophe Romain f387934886 update copyright date to 2012 2012-09-11 17:18:22 +02:00
Badlop fb39b163df Explain that 2 LDAP connections are established per vhost 2012-09-11 16:30:22 +02:00
Christophe Romain 011535f0de binary refactoring 2012-09-11 15:45:59 +02:00
Evgeniy Khramtsov 75d3152a0f Merge branch '2.1.x' into 2.2.x
Conflicts:
	src/mod_muc/mod_muc.erl
	src/mod_muc/mod_muc_room.erl
	src/mod_offline.erl
	src/mod_offline_odbc.erl
	src/mod_shared_roster.erl
	src/web/ejabberd_http_bind.erl
2012-05-04 14:19:52 +10:00
Evgeniy Khramtsov db8bd0126b Remove CRLFs introduced in the previous merge 2012-05-03 18:34:53 +10:00
Paweł Chmielowski 545f9ce525 Do not trigger item-not-found errors in mod_http_bind (part of EJABS-1827)
This changes what happens to request received with out of order rid,
previously response to such request was send immediately, and client was
free to submit another request, which triggered item-not-found if it was
delivered before request with missing rid.

This change make us wait for sending response to out of order request until
request with missing rid arrives. It also queues all outgoing data before
that condition is meet.
2012-04-27 13:19:49 +02:00
Christophe Romain 7f1e9d3972 merge from 2.1.11 and resolve conflicts 2012-04-27 11:37:11 +02:00
Paweł Chmielowski 431c34709c Make Safari happy use value from Host in WebSocket-Location header
Safari aborts connection if WebSocket-Location contains port number when
Host didn't have it, this change uses value sent by browser directly
instead of making in manually.
2012-04-11 18:12:36 +02:00
Paweł Chmielowski cf6d67ceed Always normalize case of http header names and use that fact in websocket handler
Native http parser code don't normalize header names when name is 19 or
more characters long. In websocket header module headers like that are
used, by having those headers in consistent form, code for finding
header with mixed case can be dropped.
2012-04-11 17:59:57 +02:00
Paweł Chmielowski ef0cf5d3d7 Parse and encode https header names like native http parser does
This code adds case normalization step to https headers parsing, making
it correctly use atoms for some special header no matter how upper/lower
case letters are used in input string
2012-04-11 17:24:36 +02:00
Paweł Chmielowski e99ecf6d06 Fix websocket on Safari 2012-04-11 16:07:35 +02:00
Paweł Chmielowski 83c7da3831 Handle all draft-hybi handshake in this same way 2012-04-11 16:07:29 +02:00
Paweł Chmielowski 8dc4dd7f3b Add support for newer websocket versions 2012-04-11 16:07:22 +02:00
Paweł Chmielowski 66b7caafe0 Don't use binary:match to extract lines from binaries
This was added in R13B3, lets roll our own implementation to make sure it
works on older erlang versions.
2012-04-11 16:04:05 +02:00
Paweł Chmielowski 7c0b2f5425 Parse correctly https request split into multiple packets
This fixes case when SockMod:recv() calls returns only part of first line
of http request (GET/POST/OPTION/HEAD line). Before that change request
like that (and if keep-alive was active, all further request) were dropped.

This fixes EJAB-1537.
2012-04-11 16:04:05 +02:00
Paweł Chmielowski 4645885180 Properly handle HEAD request in mod_http_bind (this fixes EJAB-1538) 2012-04-11 16:01:14 +02:00
Paweł Chmielowski 472d046426 Make sure that res is initialized in all cases 2012-04-11 16:01:11 +02:00
Christophe Romain 613d175f37 fix record_to_string, do not format the result 2012-04-10 13:33:58 +02:00
Alexey Shchepin a63bbe8a23 Merge branch '2.2.x' of git+ssh://git@gitorious.process-one.net/+ejabberd-developers/ejabberd/maincustomers.git into 2.2.x 2012-03-23 11:04:46 +02:00
Alexey Shchepin bc118986b7 Added missed tls:recv_data/2 2012-03-23 11:04:26 +02:00
Karim Gemayel 8d8dee5acf jlib.hrl : new macro ERR_POLICY_VIOLATION 2012-03-09 12:07:44 +01:00
Alexey Shchepin 92feebd0fa Merge branch '2.2.x' of git+ssh://git@gitorious.process-one.net/+ejabberd-developers/ejabberd/maincustomers.git into 2.2.x 2012-03-07 16:20:25 +02:00
Alexey Shchepin 0b423eb287 Don't ignore Length parameter in tls:recv 2012-03-07 16:19:59 +02:00
Christophe Romain 7d7c739cb3 Merge remote-tracking branch 'mainline/2.1.x' into 2.2.x 2012-02-23 16:59:22 +01:00
Alexey Shchepin 60d422eb8e Avoid quadratic behavior in reading SSL data 2012-02-20 17:41:56 +02:00
Alexey Shchepin 52df4fa024 Merge branch '2.1.x' of git+ssh://git@gitorious.process-one.net/ejabberd/mainline.git into 2.2.x
Conflicts:
	src/configure
	src/ejabberd.app
	src/ejabberd_receiver.erl
	src/tls/tls_drv.c
	src/web/ejabberd_http.erl
2012-02-20 17:29:18 +02:00
Jerome Sautret 6ebebdd02d Improve session migration lock log message. 2012-02-15 17:23:30 +01:00
Evgeniy Khramtsov e30e7686e3 Add new options: migrate_timeout and rehash_timeout 2012-02-13 23:49:44 +10:00
Evgeniy Khramtsov 290432c0ee Change a loglevel of the set_lock message 2012-02-13 23:44:00 +10:00
Christophe Romain 6563267055 make remove_user match hometree_odbc plugin on odbc version 2012-02-08 21:12:20 +01:00
Alexey Shchepin ecf7b0282e Merge branch '2.2.x' of git+ssh://git@gitorious.process-one.net/+ejabberd-developers/ejabberd/maincustomers.git into 2.2.x 2012-02-03 17:53:17 +02:00
Alexey Shchepin ea6e85d926 Use separate timer for C2S_OPEN_TIMEOUT 2012-02-03 17:53:05 +02:00
Jerome Sautret b4d107301d Added generic sha:to_hexlist/1 API function to convert sha results from
binary to hexadecimal string (TECH-1383).
2012-02-03 10:44:49 +01:00
Pablo Polvorin fead37d1c5 Avoid multiple disco#info request for caps.
Only send it when we receive the presence from the user,
if the user sends caps and we don't have it cached.
2012-01-27 16:08:28 -03:00
Alexey Shchepin eaecb9b65c Fixed ejabberd_http:get_line 2012-01-19 12:20:02 +02:00
Evgeniy Khramtsov 2948cddebf Check a node of a receiver, not a monitor.
This should fix the previous commit (EJABS-1798)
2012-01-04 16:43:10 +10:00
Evgeniy Khramtsov 438dc57def Merge branch '2.2.x' of git+ssh://gitorious.process-one.net/+ejabberd-developers/ejabberd/maincustomers into 2.2.x 2012-01-03 11:26:32 +10:00
Evgeniy Khramtsov 4d64fbb0ac Also migrate C2S sessions with remote receivers (EJABS-1798) 2012-01-03 11:25:55 +10:00
Christophe Romain e0781d9217 merge from 2.1.10 and resolve conflicts 2011-12-30 11:33:34 +01:00
Alexey Shchepin f04fe5f743 Always allow packets from user's server and bare jid in mod_privacy* 2011-12-22 16:35:56 +02:00
Alexey Shchepin 66a5aff323 Fixed the previous mod_blocking patch 2011-12-21 18:27:24 +02:00
Alexey Shchepin 5746c08f72 Corrected mod_blocking hooks return value, activate "Blocked Contacts" privacy list after it is changed 2011-12-21 16:20:59 +02:00
Alexey Shchepin 39acf823ef Ignore CDATA ping while not in session_established state 2011-12-21 09:40:30 +02:00
Evgeniy Khramtsov 2ea9e6ed59 New ejabberd command: migrate
Example usage:
$ ejabberdctl migrate 60
2011-12-21 14:56:35 +10:00
Evgeniy Khramtsov 21c75ebce5 Process "xmlns:xmpp" and "xmlns:stream" correctly (thanks to Pawel) 2011-12-16 20:10:44 +10:00
Pablo Polvorin 32e0a88edc Fix bug on s2s shaper when TLS is used
The shaper was not enabled if the remote server authenticates
using a certificate instead of dialback.
2011-12-01 13:00:52 -03:00
Alexey Shchepin bd91e2da16 Handle invalid input in ejabberd_websocket 2011-12-01 15:43:56 +02:00
Christophe Romain f3d24b6a07 Revert "added optimizations from BBC" (wrong upstream)
This reverts commit d1377da151.
2011-11-23 15:07:02 +01:00
Christophe Romain d1377da151 added optimizations from BBC 2011-11-23 15:04:24 +01:00
Pablo Polvorin d471be26cf Fix typo 2011-11-10 15:08:55 -03:00
Pablo Polvorin 31f6a9e66e Add command to persist recent MUC messages (EJABS-1785)
Example:
$ejabberdctl persist_recent_messages
Host 'localhost' , 4 messages persisted in 12 rooms
2011-11-10 12:54:11 -03:00
Pablo Polvorin d736c47649 Do not delete persistent MUC messages on restart (EJABS-1785)
Otherwise, if the server crash (not properly stopped), all recent
messages are lost.  In this case, it is better to at least keep
the outdated ones (and miss the new ones that were not saved to DB).
2011-11-10 11:07:34 -03:00
Pablo Polvorin 0e4806820e Moderate on all nodes with one command (EJABS-1733)
ejabberdctl moderate_room_history now do a multicast to
moderate the room history on all nodes on the cluster
(as the room might be replicated on different nodes).
2011-10-26 09:48:21 -03:00
Pablo Polvorin 3850b91571 Store room to disc on creation if room is persistent
If the mod_muc configuration says that rooms are
persistent by default, store the room to disc once
it is created, as there are use cases where there are
no further config after room creation, and so
the write to disc was never triggered.
2011-10-18 13:45:02 -03:00
Evgeniy Khramtsov 7b0174a626 Replace dont_concat with max_concat option 2011-10-18 23:44:00 +10:00
Evgeniy Khramtsov 2270df86d9 Use queue instead of a list in order to avoid O(N) complexity 2011-10-18 15:34:11 +10:00
Pablo Polvorin a04131c6d7 Bugfix: room history and NO_TRANSIENT_SUPERVISORS option
Fix bug that prevent ejabberd to Save room history to DB
when using the NO_TRANSIENT_SUPERVISORS compiler option.
2011-10-14 11:30:34 +02:00
Evgeniy Khramtsov e5830253b9 New BOSH option: dont_concat (EJABS-1688) 2011-10-14 15:57:15 +10:00
Evgeniy Khramtsov b7a07087d1 Fix merge conflict 2011-09-30 22:44:44 +10:00
Christophe Romain adf56dedf3 fix merge conflicts from 2.1.9 2011-09-30 14:28:40 +02:00
Christophe Romain 6bfd8b8e9a update the pubsub_odbc patch 2011-09-26 16:35:31 +02:00
Pablo Polvorin 1babae067d Persist muc history on DB on server shutdown (EJABS-1733).
Ejabberd can be configured to store recent history of MUCs
to DB before shutdown. On restart, those messages are
retrieved from storage.

To enable it, set {persist_history, true} in mod_muc configuration,
ej:
  {mod_muc,      [
                  %%{host, "conference.@HOST@"},
                  {access, muc},
                  {access_create, muc_create},
                  {access_persistent, muc_create},
                  {access_admin, muc_admin},
                  {persist_history, true}
                 ]},

Messages are only stored on server shutdown, not on the fly.

$ejabberdctl stop
or
init:stop()
inside a debug console works.

Note: Only rooms configured as "persistent" will save messages
      (as other rooms doesn't survive server restart anyway).

Limitations: There is no option to store messages on mnesia, you *must*
     use a ODBC database.  Only tested with mysql.

Check odbc/mysql.sql  for the definition of the table "room_history",
the one needed for this.
2011-09-24 18:39:03 -03:00
Pablo Polvorin 3ae4797848 Command to moderate short term muc history (part of EJABS-1733)
ejabberdctl moderate_room_history test@conference.domain.com nick

removes from short term storage all messages on
room test@conference.domain.com from nick "nick", so new user
joining the room don't get these ones.

Return the number of messages removed.
2011-09-19 15:43:20 -03:00
Evgeniy Khramtsov 86f0a9790d Do not crash on sync_send_all_state_event errors (part of EJABS-1708) 2011-09-16 16:44:24 +10:00
Evgeniy Khramtsov 54acf9bde4 Do not send <success/> twice when SCRAM-SHA-1 is used.
This is a merge bug actually
2011-09-15 19:24:41 +10:00
Evgeniy Khramtsov 8f27a697c0 Only use hash route-balancing when MUC is broadcasted 2011-09-15 08:52:22 +10:00
Evgeniy Khramtsov c9a712a16a Implement MUC rooms load distribution (TECH-1351).
Configuration example:
{domain_balancing, "conference.domain.com", broadcast}.
NOTE: both ejabberd_router and mod_muc use the option.
2011-09-14 17:43:07 +10:00
Evgeniy Khramtsov d6e81ac06b Add new domain_balancing criteria: broadcast 2011-09-14 17:40:06 +10:00
Evgeniy Khramtsov b0b371d23a Get rid of useless function clause 2011-09-05 15:06:43 +10:00
Badlop dd772404c5 Merge branch '2.1.x' into 2.2.x
Conflicts:
	src/configure
	src/ejabberd.app
	src/ejabberd_auth_anonymous.erl
	src/ejabberd_c2s.erl
	src/ejabberd_sm.erl
2011-08-24 18:29:25 +02:00
Pablo Polvorin bed5e80ef9 Merge commit '78f50c5' into 2.2.x 2011-08-17 15:23:16 -03:00
Christophe Romain 9ccdb5d78b fix set_configure with odbc backend (thanks to Karim Gemayel) 2011-08-17 16:18:32 +02:00
Evgeniy Khramtsov 5bef1a8f77 Now it is possible to migrate C2S/BOSH/MUC sessions.
Example usage:
$ ejabberdctl stop_migrate 30
This will migrate c2s/bosh/muc processes smoothly within 30 seconds and stop ejabberd.

The commit also resolves EJABS-1661
2011-08-13 19:05:21 +10:00
Evgeniy Khramtsov 4f1637fa40 Implement BOSH session migration 2011-08-12 23:48:39 +10:00
Evgeniy Khramtsov 796cb6634b Get rid of sync call in send/2, process send_xml/2 failure gracefully 2011-08-05 18:10:56 +10:00
Evgeniy Khramtsov bb5480756a Get rid of "ip" state value 2011-08-05 18:04:01 +10:00
Evgeniy Khramtsov edb030f49a Get rid of "socket" state value 2011-08-05 17:58:02 +10:00
Evgeniy Khramtsov 0ed4ceebea Complete API functions 2011-08-05 17:52:49 +10:00
Evgeniy Khramtsov 31f7eadfca Use ?GEN_FSM macro whenever possible 2011-08-05 17:02:47 +10:00
Evgeniy Khramtsov 1c72c45404 Add shaper support 2011-08-05 15:53:57 +10:00
Evgeniy Khramtsov f8fd9969e1 Return valid "inactivity" in session creation response 2011-07-28 16:39:17 +10:00
Evgeniy Khramtsov 8d09655a89 Reply on stream:start immediately if XMPP version is lower than 1.0 2011-07-28 16:31:10 +10:00
Evgeniy Khramtsov a06b627631 Fix try/catch branch 2011-07-28 16:04:02 +10:00
Evgeniy Khramtsov cb41c8ef80 Make work with buffers more abstract 2011-07-27 13:14:10 +10:00
Evgeniy Khramtsov d4cea0f78f Fix possible function clause 2011-07-27 12:12:44 +10:00
Evgeniy Khramtsov 4d20abd7b6 Process max_inactivity and max_pause config options 2011-07-26 21:44:35 +10:00
Evgeniy Khramtsov 351ad528f9 Prebind support 2011-07-26 19:27:54 +10:00
Evgeniy Khramtsov 006da5589e Fix copyright header 2011-07-26 16:24:21 +10:00
Evgeniy Khramtsov 5f32dd3959 Use HTTP reason phrase to describe terminal binding errors 2011-07-26 16:19:04 +10:00
Evgeniy Khramtsov a9269df2aa Fix inactivity timer processing 2011-07-26 15:15:17 +10:00
Evgeniy Khramtsov a7d82d6ecb New BOSH implementation 2011-07-25 23:53:33 +10:00
Evgeniy Khramtsov 5b10b58c9f Do not hash s2s connections 2011-07-22 19:48:22 +10:00
Christophe Romain ae24f7d787 send publish hook only on success, with broadcast stanza 2011-07-18 12:26:43 +02:00
Mickaël Rémond 1dfd9fd568 Merge branch '2.2.x' of git+ssh://gitorious.process-one.net/+ejabberd-developers/ejabberd/maincustomers into 2.2.x 2011-07-15 20:21:13 +02:00
Mickaël Rémond f655ab2ffc Allow to dump a specific user session 2011-07-15 20:20:56 +02:00
Evgeniy Khramtsov 302294faec HTTP prebinding support (TECH-1327)
Example configuration:
{modules,
 [
  ...
  {mod_http_bind, [{prebind, true}]},
  ...
]}
2011-07-06 18:04:26 +10:00
Alexey Shchepin b6a637c121 Minor mod_version bugfix 2011-07-03 19:03:56 +03:00
Alexey Shchepin 60009ece44 Optimized mod_roster_odbc:get_roster 2011-07-03 19:03:42 +03:00
Evgeniy Khramtsov 41fad8956b Merge branch '2.1.x' into 2.2.x
Conflicts:
	src/ejabberd_c2s.erl
2011-05-30 23:29:41 +10:00
Evgeniy Khramtsov f0c32433dc Fix race condition (EJABS-1677) 2011-05-30 10:00:24 +02:00
Eric Cestari 78f50c58bf Merge branch '2.2.x' of gitorious.process-one.net:+ejabberd-developers/ejabberd/maincustomers into 2.2.x 2011-05-27 10:41:48 +02:00
Badlop 133b8d42a3 Disable all entity expansions (thanks to Alexey Shchepin)(EJAB-1451) 2011-05-24 13:12:28 +02:00
Christophe Romain 3785b3e951 add index migration code 2011-05-16 17:19:42 +02:00
Evgeniy Khramtsov 70e1545d3a Monitor only noconnection events 2011-05-16 18:01:51 +10:00
Alexey Shchepin 8aaf9bffa0 Resend queue to self before calling terminate 2011-05-13 14:53:04 +03:00
Eric Cestari d65b785f5d Closing properly the XMPP websocket process 2011-05-09 11:02:22 +02:00
Eric Cestari 9aabd59a1f Merge branch '2.2.x' of gitorious.process-one.net:+ejabberd-developers/ejabberd/maincustomers into 2.2.x 2011-05-09 10:51:43 +02:00
Evgeniy Khramtsov 8806fdc1c2 Implement C2S redirection
- The feature is based on <see-other-host/> stream error, see RFC6120, 4.9.3.19
- To enable the feature you must set {redirect, true} in C2S listener section and set global "hostname" option on all nodes in cluster. The hostname must be string in the form as described in the RFC, for example: "foo.org", "foo.org:5222", "1.2.3.4", "[2001:41D0:1:A49b::1]:9222" and so on
2011-05-09 14:02:08 +10:00
Evgeniy Khramtsov 1922bf21f0 Do not try to start TLS twice when front-end socket is used 2011-05-05 19:02:34 +10:00
Evgeniy Khramtsov c98ddeb59f Merge branch '2.1.x' into 2.2.x
Conflicts:
	src/ejabberd_captcha.erl
	src/expat_erl.c
	src/mod_muc/mod_muc_room.erl
2011-05-04 00:04:10 +10:00
Evgeniy Khramtsov 613214da18 Do not add p1:pushed more than once 2011-05-03 23:01:05 +10:00
Evgeniy Khramtsov 38693a670b Process ejabberd_sm messages using several dispatchers (EJABS-1653) 2011-05-02 22:37:33 +10:00
Evgeniy Khramtsov a97a60a888 Fix previous merge 2011-04-29 20:53:15 +10:00
Evgeniy Khramtsov 49365da481 Stringprep JID before get_node calculation 2011-04-27 15:22:25 +10:00
jabber 70e84021f2 Remove global lock if there are no nodes available 2011-04-27 15:17:54 +10:00
Evgeniy Khramtsov 24e033ac79 Initialize cluster before modules start 2011-04-27 15:15:49 +10:00
Evgeniy Khramtsov 658ab235ba Get rid of pg2 in cluster nodes 2011-04-27 15:15:19 +10:00
Evgeniy Khramtsov 2f16a160c0 Shadow unused variable 2011-04-27 15:07:18 +10:00
Evgeniy Khramtsov 4a2f62062e New migration procedure 2011-04-27 15:07:10 +10:00
Christophe Romain 33d4126290 merge with latest 2.1.x (pre 2.1.7) 2011-04-11 15:47:04 +02:00
Eric Cestari 87315e92a8 Merge branch '2.2.x' of gitorious.process-one.net:+ejabberd-developers/ejabberd/maincustomers into 2.2.x 2011-04-07 11:47:20 +02:00
Alexey Shchepin 494add4fd0 Updated rebind from the latest 2.2.x-applepush branch 2011-03-21 19:11:05 +02:00
Christophe Romain 3b7458bbc2 fir state initialization 2011-03-18 18:59:44 +01:00
Christophe Romain f05a4d1638 typo fix 2011-03-18 17:41:56 +01:00
Christophe Romain 75d2cbcb14 add nodeidx as index on pubsub_state and pubsub_item 2011-03-18 17:36:08 +01:00
Christophe Romain f9fa168d84 prevent from creating empty pubsub_subscription record 2011-03-18 15:17:13 +01:00
Christophe Romain 5ad1d08b89 SSL sockets don't compute length of data (EJABS-1460) 2011-03-15 13:53:38 +01:00
Christophe Romain dcb068c7ad Correctly handle ssl requests split into multiple ip (EJABS-1460) 2011-03-15 13:52:35 +01:00
Christophe Romain 2d32d2f25e Enable workarounds for broken clients in tls layer (EJABS-1460) 2011-03-15 13:51:49 +01:00
Eric Cestari 307e57a105 Merge branch '2.2.x' of gitorious.process-one.net:+ejabberd-developers/ejabberd/maincustomers into 2.2.x 2011-02-17 12:25:15 +01:00
Christophe Romain 8e68e89816 Merge remote branch 'mainline/2.1.x' into 2.2.x 2011-02-15 10:48:27 +01:00
Eric Cestari 1564060c6c Closing properly the XMPP websocket process 2011-02-14 14:48:02 +01:00
Christophe Romain f39ccd73c5 Merge remote branch 'mainline/2.1.x' into 2.2.x 2011-02-14 13:54:06 +01:00
Evgeniy Khramtsov 01689bc6b9 Ack support (TECH-1261) 2011-02-11 13:42:55 +09:00
Christophe Romain 024a80d41f port previous pubsub changes to _odbc 2011-02-08 18:29:52 +01:00
Christophe Romain f485109c39 refactor pubsub broadcast to allow big optimization 2011-02-08 17:14:19 +01:00
Eric Cestari bde46896d6 Merge branch '2.2.x' of gitorious.process-one.net:+ejabberd-developers/ejabberd/maincustomers into 2.2.x 2011-02-08 16:39:38 +01:00
Eric Cestari 0c30b012f7 Websocket: corrects bug of ejabberd dropping connection under message rate. 2011-02-08 16:39:13 +01:00
Badlop 14b39a0ee4 Merge remote branch 'origin/2.1.x' into 2.2.x
Conflicts:
	src/web/ejabberd_http_bind.erl
2011-01-31 18:57:13 +01:00
Eric Cestari e380eee223 WebSocket support update
- added JSON encoding
- fix problem where session was not closed
- origin can now be decided by a custom module
2011-01-19 14:54:20 +01:00
Eric Cestari 1959546ff9 Merge branch '2.2.x' of gitorious.process-one.net:+ejabberd-developers/ejabberd/maincustomers into 2.2.x 2011-01-19 14:49:45 +01:00
Christophe Romain 92f5509b35 improve check_start only matching node process 2011-01-18 13:36:46 +01:00
Christophe Romain 1a2e6b02ab sync with latest 2.1.6 befor tagging 2011-01-12 12:11:04 +01:00
Eric Cestari 56bf156b6f logging works on non-configured hosts.
In the log file, information should be logged under the default hostname.
2011-01-11 12:55:03 +01:00
Eric Cestari 5632901820 Fixed 2.1.6 compile error 2011-01-07 16:00:10 +01:00
Eric Cestari 92b6c12420 Merge branch '2.2.x' of gitorious.process-one.net:+ejabberd-developers/ejabberd/maincustomers into 2.2.x 2011-01-07 15:54:00 +01:00
Eric Cestari 062d58026a mod_http_fileserver.erl will only conditionally gzip content by checking Accept-Encoding. 2011-01-07 15:28:26 +01:00
Eric Cestari 7ef85dddea Refactoring of ejabberd_http_fileserver.erl
- not a gen_server anymore. Should be way faster now (no more message passing between processes)
- configuration stored in mochiglobal
- support for etag
- support for gzip compression: 
	- static (if a foo.gz is in the same dir as requested foo, it will be served)
	- always (will always gzip, will use static is available)
	- false, don't gzip
- logfile is now in another module.
2011-01-07 15:12:51 +01:00
Mickaël Rémond 4a9e7f0a3a Use route instead of send_element to go through standard workflow Offline messages should thus be tracked for ack if needed (TEXTO-226).
Signed-off-by: Evgeniy Khramtsov <ekhramtsov@process-one.net>
2011-01-05 14:36:21 +01:00
Christophe Romain cffe224d4a log and drop messages only from autofilter 2011-01-03 15:26:44 +01:00
Christophe Romain 15c27c9ddd fix bad jid issue 2011-01-03 09:52:12 +01:00
Evgeniy Khramtsov 149f8e2b45 Merge remote branch 'mainline-2.1.x/2.1.x' into 2.2.x
Conflicts:
	src/ejabberd.app
2010-12-28 21:17:01 +09:00
Eric Cestari 2ab31cb613 Merge branch '2.2.x-applepush' into 2.2.x
Without applepush
Conflicts:
	src/ejabberd_c2s.erl
	src/ejabberd_c2s.hrl
2010-12-23 15:30:14 +01:00
Evgeniy Khramtsov 03870f962c Fix user_receive_packet hook 2010-12-16 23:54:02 +09:00
Evgeniy Khramtsov 405e9b24b0 Fix get_sessions/2 function 2010-12-16 23:47:53 +09:00
Evgeniy Khramtsov 3c51ca06d5 Merge branch '2.2.x' into mergefix 2010-12-14 23:19:31 +09:00
Evgeniy Khramtsov 02cfb11a6d Merge branch '2.1.x' into mergefix
Conflicts:
	.gitignore
	src/ejabberd.app
	src/ejabberd_c2s.erl
	src/ejabberd_captcha.erl
	src/ejabberd_node_groups.erl
	src/mod_caps.erl
	src/web/ejabberd_http.erl
	src/web/ejabberd_http_bind.erl
2010-12-14 23:10:08 +09:00
Christophe Romain 4e875c7fb7 manual merge from 2.1.6 DO NOT MERGE, NEED TESTS 2010-12-13 23:44:53 +01:00
Alexey Shchepin 21f2817f40 Merge branch '2.2.x' of git+ssh://git@gitorious.process-one.net/+ejabberd-developers/ejabberd/maincustomers.git into 2.2.x 2010-12-03 16:40:22 +02:00
Alexey Shchepin 31e4ccf78b Fixed "To" variable in ejabberd_c2s:roster_change 2010-12-03 16:39:04 +02:00
Evgeniy Khramtsov bfedd21c98 Disable error/1 auto-import (introduced in R14) 2010-12-03 23:38:18 +09:00
Evgeniy Khramtsov 9f3cdad3f7 Do not add "jabber:x:delay" more than once 2010-12-01 15:19:07 +02:00
Alexey Shchepin 931866ee33 Added ssl:connect timeout 2010-12-01 15:18:46 +02:00
Alexey Shchepin b3facf092a Don't loop when there is nothing after a stream start 2010-11-25 20:33:51 +02:00
Christophe Romain 70c1e1d0b1 enforce pubsub cleaner 2010-11-04 16:54:24 +01:00
Alexey Shchepin aea394861d Added a protocol for a client to send the number of local unread messages
Conflicts:

	src/ejabberd_c2s.erl
2010-10-25 10:09:06 +03:00
Badlop 2e33904bb8 Don't check whether the contact is a locally registered account or not (EJABS-1550) 2010-10-24 00:48:57 +02:00
Badlop 2d3bbd43d7 Allow add_rosteritem functions to work even when no know mod_roster is enabled 2010-10-21 21:07:07 +02:00
Badlop 6c0e9ef575 Fix return values of some functions. newgroups argument changed to groups. 2010-10-21 00:23:33 +02:00
Badlop ca62271a89 Apply Apollo fixes. More fixes. Improve command descriptions. 2010-10-20 16:41:27 +02:00
Evgeniy Khramtsov c96a1805e8 - get rid of rpc:call to avoid group leader inheritance
- do not log migration errors
- remove stopping node from cluster hashing explicitly
2010-10-20 17:26:01 +10:00
Badlop babff870a8 Remove custom ON command: send_notification/6 2010-10-19 17:17:55 +02:00
Badlop 5cd3de9cd7 Copy changes from Apollo's mod_xmlrpc to 2.2.x's mod_xmlrpc
Changes:
* link_contacts new arguments: group1::string, group2::string
* New method add_rosteritem_groups/5
* New method del_rosteritem_groups/5
* New method modify_rosteritem_groups/7
* get_roster change argument group::string -> groups::[string]
2010-10-19 16:55:24 +02:00
Badlop 437d8c6b7c Copy ejabberd_xmlrpc from ejabberd-modules SVN 2010-10-19 16:51:28 +02:00
Badlop 440eef74e9 Copy xmlrpc-1.13 source code 2010-10-19 16:51:24 +02:00
Christophe Romain c849552177 fix add_rosteritem issue (TECH-1181) 2010-10-19 15:19:41 +02:00
Alexey Shchepin 6134c67df4 Merge remote branch '2.2.x/2.2.x' into 2.2.x-applepush 2010-10-19 14:02:14 +03:00
Alexey Shchepin aa60140ba8 Revert "Merge ApplePush to 2.2.x"
This reverts commit b8b6fc0da5.

Conflicts:

	src/mod_applepush.erl
	src/mod_applepush_service.erl
2010-10-19 13:53:10 +03:00
Alexey Shchepin 59135cac6f Revert "ApplePush : previous merge missed timeout handler in c2s."
This reverts commit 40625b29f2.
2010-10-19 13:52:46 +03:00
Alexey Shchepin 8d69d4aaba Revert "Merge branch '2.1.x-applepush' of git@gitorious.process-one.net:+applepush/ejabberd/applepush.git into aplepush-test"
This reverts commit 00d8b2ac30, reversing
changes made to cac23c39c9.
2010-10-19 13:52:17 +03:00
Alexey Shchepin 426b7ca769 Revert "Merge branch '2.1.x-applepush' of git@gitorious.process-one.net:+applepush/ejabberd/applepush.git into 2.2.x"
This reverts commit ba326eb976, reversing
changes made to 00d8b2ac30.
2010-10-19 13:52:09 +03:00
Alexey Shchepin b61d16dd33 Revert "Merge remote branch 'applepush/2.1.x-applepush' into 2.2.x"
This reverts commit f76dcd0d48, reversing
changes made to 7da8d9e4e3.
2010-10-19 13:51:44 +03:00
Alexey Shchepin 807af3c08a Merge branch '2.2.x' of git+ssh://git@gitorious.process-one.net/+ejabberd-developers/ejabberd/maincustomers.git into 2.2.x-applepush 2010-10-19 13:08:46 +03:00
Badlop d07424365d Fix bug in mod_pubsub in_subscription return value 2010-10-19 00:25:14 +02:00
Badlop 70fe2948b9 Revert "Remove some compiled files"
That removal was only intended for ejabberd master,
as it requires also changes in gitignore, Makefile.in and aclocal.m4

This reverts commit 179a0cf255.
2010-10-18 23:17:12 +02:00
Evgeniy Khramtsov a5166f3946 copied feature_inspect_packet hook from iphone svn repo 2010-10-15 23:13:29 +10:00
Juan Pablo Carlino 11b00b92e9 merge from Team Leader 2.2 (r973) 2010-10-14 19:00:19 -03:00
Alexey Shchepin c10e43f95f Improved behaviour on SSL handshake failure 2010-10-14 15:59:23 +03:00
Evgeniy Khramtsov eeffc77a1a ignore RPC timeout during migration 2010-10-14 20:29:45 +10:00
Evgeniy Khramtsov 254686ab46 fixes timeout calculation 2010-10-14 20:15:53 +10:00
Evgeniy Khramtsov 4a6fc46713 increase rehash timeout to 30 seconds; increase hashing points 2010-10-14 20:02:34 +10:00
Christophe Romain bde3bce1e7 remove non generic comment 2010-10-13 15:26:38 +02:00
Christophe Romain f76dcd0d48 Merge remote branch 'applepush/2.1.x-applepush' into 2.2.x 2010-10-13 12:36:04 +02:00
Christophe Romain 7da8d9e4e3 merge resolved against latest 2.1.x 2010-10-13 11:02:22 +02:00
Evgeniy Khramtsov 3a7d02dbd3 fixes anonymous sessions lookup 2010-10-09 00:44:23 +10:00
Evgeniy Khramtsov 350af319bf fixes annoying crash with controller change 2010-10-08 19:26:49 +10:00
Christophe Romain f81473fc65 fix licence issue and (c) to 2010 2010-09-28 13:36:16 +02:00
Christophe Romain b6dcd41225 added antiflood and filter modules from TeamLeader 2010-09-24 16:11:59 +02:00
Christophe Romain db2baa8f84 pubsub clean now cluster aware 2010-09-24 16:11:39 +02:00
Christophe Romain a894d25b1f s2s and session are no longer part of replication init of joincluster 2010-09-24 16:11:12 +02:00
Alexey Shchepin a93991bef2 Mark out-of-reception sessions in #session.info 2010-09-23 18:14:04 +03:00
Alexey Shchepin 7127d067c8 Revert the previous change, as priority is 0 by default 2010-09-23 18:05:56 +03:00
Alexey Shchepin ba326eb976 Merge branch '2.1.x-applepush' of git@gitorious.process-one.net:+applepush/ejabberd/applepush.git into 2.2.x 2010-09-23 16:22:03 +03:00
Alexey Shchepin fd50b2169b Insert "priority" element in out-of-reception presences 2010-09-23 16:18:53 +03:00
Alexey Shchepin 00d8b2ac30 Merge branch '2.1.x-applepush' of git@gitorious.process-one.net:+applepush/ejabberd/applepush.git into aplepush-test
Conflicts:
	src/ejabberd_c2s.erl
	src/mod_offline.erl
	src/mod_offline_odbc.erl
2010-09-22 22:38:32 +03:00
Alexey Shchepin cac23c39c9 Disable notifications for a user on "Invalid token" error 2010-09-22 22:19:36 +03:00
Alexey Shchepin a5813b798f Fixed "sender" log field 2010-09-22 22:19:17 +03:00
Evgeniy Khramtsov 191cd2af3c different hooks should be called for session migration and session close 2010-09-21 03:17:52 +10:00
Alexey Shchepin f2cfee11de Disable notifications for a user on "Invalid token" error 2010-09-20 13:35:42 +03:00
Eric Cestari b0c79c57b0 Merge branch '2.2.x' of gitorious.process-one.net:+ejabberd-developers/ejabberd/maincustomers into 2.2.x 2010-09-17 16:26:09 +02:00
Eric Cestari 8ea523889b [TECH-1151] Websockets are now handled in pure binary 2010-09-17 16:10:59 +02:00
Eric Cestari b44c462b0e [TECH-1151] IP now correctly stored 2010-09-17 14:49:04 +02:00
Eric Cestari 0987700a27 Rename protocol version 76 to 00 (new official name) 2010-09-17 14:24:24 +02:00
Eric Cestari ff4f052bb1 [TECH-1151] Origin and Protocol parameters are configurable and set. 2010-09-17 14:23:34 +02:00
Christophe Romain 100b821c1a added customer related tools 2010-09-17 09:11:03 +02:00
Christophe Romain 893c47a2e0 add ability to retreive only node names 2010-09-17 07:28:28 +02:00
Christophe Romain 694af69982 ejabberd.app now set to version 2.2.x 2010-09-17 06:46:40 +02:00
Christophe Romain c576f340f9 upgrade to lattest pubsub schema 2010-09-17 06:40:48 +02:00
Badlop 179a0cf255 Remove some compiled files 2010-09-17 00:14:13 +02:00
Eric Cestari a45ecb70ff [TECH-1511] debug traces reorganized 2010-09-16 15:08:53 +02:00
Christophe Romain df1ab9149f remove garbage configuration 2010-09-16 14:53:20 +02:00
Eric Cestari cb54444f00 Merge branch '2.2.x' into websockets 2010-09-16 14:44:44 +02:00
Eric Cestari c77e7fbb7d Merge branch '2.2.x' of gitorious.process-one.net:+ejabberd-developers/ejabberd/maincustomers into 2.2.x 2010-09-16 14:38:52 +02:00
Eric Cestari 40625b29f2 ApplePush : previous merge missed timeout handler in c2s. 2010-09-16 14:37:27 +02:00
Christophe Romain 2624f3ba51 added pubsub helper modules 2010-09-16 14:31:08 +02:00
Eric Cestari 44832e12b3 Merge branch '2.2.x' into websockets 2010-09-16 11:07:12 +02:00
Eric Cestari caa8d0c411 Merge branch '2.2.x' of git+ssh://gitorious.process-one.net/~ecestari/ejabberd/ecestaris-maincustomers into 2.2.x 2010-09-16 10:54:45 +02:00
Eric Cestari 7e72d18292 Merge branch 'websockets' of git+ssh://gitorious.process-one.net/~ecestari/ejabberd/ecestaris-maincustomers into websockets 2010-09-15 17:21:20 +02:00
Eric Cestari b0a81778af [TECH-1511] preliminary XMPP support via websockets 2010-09-15 17:20:54 +02:00
Christophe Romain 652774a83c remove obsolete files 2010-09-15 13:51:46 +02:00
Alexey Shchepin 2aea503a2a Don't resend badge if there are no offline messages 2010-09-14 21:27:02 +02:00
Alexey Shchepin 0d8aacb3e7 Do not disable push on send error 2010-09-14 21:26:50 +02:00
Alexey Shchepin e6be70943f Added badge resending functions 2010-09-14 21:26:36 +02:00
Alexey Shchepin c86e4faba3 Fixed "sender" log field 2010-09-14 18:00:01 +03:00
Christophe Romain c3c06ccd1c Merge remote branch 'mainline/2.1.x' into 2.2.x 2010-09-14 16:59:46 +02:00
Eric Cestari 18b569a356 [TECH-1511] preliminary XMPP support via websockets 2010-09-13 17:26:24 +02:00
Alexey Shchepin 261acfce54 Don't resend badge if there are no offline messages 2010-09-13 15:46:39 +03:00
Eric Cestari c8567f1de2 [TECH-1511] Calls start() on handler to get a PID 2010-09-13 14:23:42 +02:00
Eric Cestari 35a0e27d04 [TECH-1511] clean support for websockets.
Added handlers in configuration file
2010-09-13 12:04:52 +02:00
Alexey Shchepin 73f7b2ba38 Do not disable push on send error 2010-09-13 06:22:14 +03:00
Alexey Shchepin 8a693df6e6 Added badge resending functions 2010-09-13 06:19:38 +03:00
Eric Cestari c41bdea1f1 [TECH-1511] rough support for websockets 2010-09-10 17:14:58 +02:00
Eric Cestari cccbf7de12 [TECH-1151] websockets are properly detected. 2010-09-10 15:04:19 +02:00
Eric Cestari 660a2735f0 mod_keepalive added to repos 2010-09-10 14:11:56 +02:00
Eric Cestari 77136bccdf [TECH-1151] websocket initial code 2010-09-10 14:06:26 +02:00
Eric Cestari b8b6fc0da5 Merge ApplePush to 2.2.x 2010-09-09 17:00:18 +02:00
Eric Cestari 8ecf8d7e27 A few additions to .gitignore 2010-09-09 16:16:46 +02:00
Eric Cestari 4134edf8de Merge ApplePush to branch 2.2.x 2010-09-09 16:16:28 +02:00
Eric Cestari a77d53d738 [TECH-1068] Added missing catch in process function 2010-09-08 17:25:37 +02:00
Eric Cestari 49a3424a26 add *.so to .gitignore 2010-09-08 17:21:49 +02:00
Eric Cestari 92a60ff7fd flash hack merge fix from BBC 2010-09-08 17:03:49 +02:00
Eric Cestari 33c7d36a95 Merge branch '2.2.x' of git+ssh://git@gitorious.process-one.net/+ejabberd-developers/ejabberd/maincustomers into 2.2.x 2010-09-08 16:54:26 +02:00
Christophe Romain 6c7316cbdd apply flash hack patch 2010-09-08 16:51:06 +02:00
Eric Cestari 09da9eeb95 Merge branch '2.2.x' of git+ssh://git@gitorious.process-one.net/+ejabberd-developers/ejabberd/maincustomers into 2.2.x 2010-09-08 15:32:21 +02:00
Christophe Romain 76d4ba66b2 merge 2.1.x to 2.2.x 2010-09-08 15:30:52 +02:00
Eric Cestari f284fc3284 [TECH-1068] Atom feed is good enough. 2010-09-08 15:30:28 +02:00
Eric Cestari 86a59fb469 Implemented rough access_model access control. 2010-09-07 17:23:13 +02:00
Eric Cestari 31da259a75 HTTP Delete item 2010-09-07 16:42:12 +02:00
Eric Cestari 363711a370 New features :
- edit an item
- edit node configuration
2010-09-07 16:22:57 +02:00
Eric Cestari bf98fa0c01 Added node creation with configure form
Added deletion
Better behavior in case of a crash (returns 500)
2010-09-07 14:35:40 +02:00
Eric Cestari cd923838c3 Making progress on the Atom interface.
- GET items
- POST items
- GET nodes

HTTP error codes now are the ones XMPP returns.
2010-09-07 11:32:14 +02:00
Eric Cestari a22ebd3c49 Added support for GET a single item
and GET an atom feed of a node
2010-09-03 15:54:51 +02:00
Eric Cestari 353d16b8ef Post to pubsub using http POST :
{5280, ejabberd_http, [
			 http_poll, 
			 web_admin,
			 {request_handlers, [{["pshb"], pshb_http}]} % this should be added
			]}

 To post to a node the content of the file "sam.atom" on the "foo", on the localhost virtual host, using cstar@localhost
  curl -u cstar@localhost:encore  -i -X POST  http://localhost:5280/pshb/localhost/foo -d @sam.atom
2010-09-02 16:57:21 +02:00
Alexey Shchepin 6bb0dc12f1 Cut payload when it's too big 2010-09-02 13:41:18 +03:00
Alexey Shchepin ad00ec1518 Added xml:remove_subtags (thanks to Mickael Remond) 2010-09-02 13:40:45 +03:00
Christophe Romain c03140d4be fix merge issue 2010-08-30 11:14:57 +02:00
Alexey Shchepin ea8aa1f25b clean p1:pushed tag (thanks to Mickael Remond) 2010-08-19 15:53:44 +03:00
Alexey Shchepin 8fe6ed011d Merge branch '2.1.x' of git://github.com/processone/ejabberd.git into applepush 2010-08-19 15:39:08 +03:00
Alexey Shchepin 35cde6787d Initial applepush git commit 2010-08-19 15:30:39 +03:00
Christophe Romain 23b28ec60f Merge remote branch 'mainline/2.1.x' into 2.2.x 2010-08-09 10:04:11 +02:00
Christophe Romain 59ae9bea76 added p1 modules 2010-08-05 14:23:26 +02:00
Christophe Romain 7be707f7bc Merge branch '2.1.x' into 2.2.x 2010-08-05 10:20:47 +02:00
Christophe Romain 200815dcdb merge from latest 2.1.x 2010-07-22 12:01:44 +02:00
Christophe Romain 2d1c416daf Allow roster change from external component (TECH-1001) 2010-07-22 11:03:07 +02:00
Christophe Romain 3aaebe98f4 add ejabberdctl ability to check epmd names (TECH-1121) 2010-07-20 14:06:48 +02:00
Christophe Romain 2ee7642816 add missing hrl 2010-07-16 18:57:00 +02:00
Christophe Romain bf63d09d80 Add etop command to ejabberdctl (TECH-1109) 2010-07-16 16:52:27 +02:00
Christophe Romain 28c4c87956 Added catches to reset_stream calls to avoid errors during a race condition (thanks to Aleksey Shchepin) 2010-07-13 21:54:46 +02:00
Christophe Romain d0b7cd599b Make chat room destroy and create being sync_dirty to limit mnesia overload. (thanks to Mickael Remond) 2010-07-13 21:48:36 +02:00
Christophe Romain cc1839a250 Try forcing usage of cache for all MySQL sessions, and add correct timeout on odbc driver query. (thanks to Mickael Remond) 2010-07-13 19:06:12 +02:00
Christophe Romain 7d37715f8b Add rate limit command to ejabberd_listener. You can now limit the max number of TCP connects per second on a given port. (thanks to Mickael Remond) 2010-07-13 19:00:49 +02:00
Christophe Romain 091b4568d5 Add module to log informations when Mnesia is overloaded, and also supports rate limitation 2010-07-13 18:46:04 +02:00
Christophe Romain cc0503fd5e Add module to dump c2s connection 2010-07-13 18:45:49 +02:00
Christophe Romain 4862251f34 Add gitignore 2010-07-13 18:45:32 +02:00
Christophe Romain 987d796439 fix duplicated function 2010-07-13 12:48:52 +02:00
Christophe Romain 628571f8cf merge from ekhramtsov-ejabberd, which is latest 2.1.x with consistent hash 2010-07-13 12:04:30 +02:00
418 changed files with 105481 additions and 78059 deletions
-20
View File
@@ -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
View File
@@ -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
+6
View File
@@ -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
+1 -3
View File
@@ -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
+1538 -3225
View File
File diff suppressed because it is too large Load Diff
+266
View File
@@ -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
View File
-5
View File
@@ -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
View File
@@ -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
+6184
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -1210,7 +1210,7 @@ attacks.
</LI><LI CLASS="li-itemize">You may want to allow login access only for certain users. <TT>pam_listfile.so</TT>
module provides such functionality.
</LI><LI CLASS="li-itemize">If you use <TT>pam_winbind</TT> to authorise against a Windows Active Directory,
then <TT>/etc/nssswitch.conf</TT> must be configured to use <TT>winbind</TT> as well.
then <TT>/etc/nsswitch.conf</TT> must be configured to use <TT>winbind</TT> as well.
</LI></UL><P> <A NAME="accessrules"></A> </P><!--TOC subsection Access Rules-->
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc25">3.1.5</A>&#XA0;&#XA0;<A HREF="#accessrules">Access Rules</A></H3><!--SEC END --><P> <A NAME="accessrules"></A>
</P><P> <A NAME="ACLDefinition"></A> </P><!--TOC subsubsection ACL Definition-->
@@ -4499,7 +4499,7 @@ Alexey Shchepin (<A HREF="xmpp:aleksey@jabber.ru"><TT>xmpp:aleksey@jabber.ru</TT
</LI><LI CLASS="li-itemize">Vsevolod Pelipas (<A HREF="xmpp:vsevoload@jabber.ru"><TT>xmpp:vsevoload@jabber.ru</TT></A>)
</LI></UL><P> <A NAME="copyright"></A> </P><!--TOC chapter Copyright Information-->
<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc103">Appendix&#XA0;D</A>&#XA0;&#XA0;<A HREF="#copyright">Copyright Information</A></H1><!--SEC END --><P> <A NAME="copyright"></A> </P><P>Ejabberd Installation and Operation Guide.<BR>
Copyright &#XA9; 2003 &#X2014; 2012 ProcessOne</P><P>This document is free software; you can redistribute it and/or
Copyright &#XA9; 2003 &#X2014; 2013 ProcessOne</P><P>This document 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.</P><P>This document is distributed in the hope that it will be useful,
+149 -86
View File
@@ -82,6 +82,7 @@
\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}}
@@ -253,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).
@@ -383,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.
@@ -398,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}
@@ -834,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}
@@ -843,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
@@ -950,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,
@@ -1096,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
@@ -1126,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},
@@ -1145,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"}]}
@@ -1223,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.
@@ -1241,7 +1300,7 @@ The option \option{fqdn} allows you to define the Fully Qualified Domain Name
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:
\esyntax{\{fqdn, undefined|FqdnString\}.}
\esyntax{\{fqdn, undefined|FqdnString|[FqdnString]\}.}
\makesubsubsection{internalauth}{Internal}
\ind{internal authentication}\ind{Mnesia}
@@ -1451,7 +1510,7 @@ attacks.
\item You may want to allow login access only for certain users. \term{pam\_listfile.so}
module provides such functionality.
\item If you use \term{pam\_winbind} to authorise against a Windows Active Directory,
then \term{/etc/nssswitch.conf} must be configured to use \term{winbind} as well.
then \term{/etc/nsswitch.conf} must be configured to use \term{winbind} as well.
\end{itemize}
\makesubsection{accessrules}{Access Rules}
@@ -1938,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.
@@ -1953,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}
@@ -2038,16 +2085,9 @@ 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}
@@ -2056,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}
@@ -2077,8 +2126,7 @@ 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}
@@ -2096,13 +2144,7 @@ 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.
@@ -2114,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}
@@ -2193,31 +2227,6 @@ 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}
@@ -2601,6 +2610,7 @@ The following table lists all modules included in \ejabberd{}.
\hline \ahrefloc{modmuc}{\modmuc{}} & Multi-User Chat (\xepref{0045}) & \\
\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}) & \\
@@ -3562,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{}}
@@ -5125,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).
@@ -5185,6 +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{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.
@@ -5917,7 +5980,7 @@ Thanks to all people who contributed to this guide:
\makechapter{copyright}{Copyright Information}
Ejabberd Installation and Operation Guide.\\
Copyright \copyright{} 2003 --- 2012 ProcessOne
Copyright \copyright{} 2003 --- 2013 ProcessOne
This document is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
+146
View File
@@ -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
+99
View File
@@ -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 -1
View File
@@ -1,2 +1,2 @@
% ejabberd version (automatically generated).
\newcommand{\version}{2.1.11}
\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,
%% [
+120 -81
View File
@@ -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,18 +43,21 @@ 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
NODE=${ERLANG_NODE%@*}
fi
# check the proper system user is used
@@ -62,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
@@ -87,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
@@ -143,6 +152,7 @@ export EXEC_CMD
# start server
start ()
{
check_start
$EXEC_CMD "$ERL \
$NAME $ERLANG_NODE \
-noinput -detached \
@@ -174,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'`
@@ -189,6 +199,7 @@ debug ()
# start interactive server
live ()
{
check_start
echo "--------------------------------------------------------------------"
echo ""
echo "IMPORTANT: ejabberd is going to start in LIVE (interactive) mode."
@@ -205,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 \
@@ -217,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 ""
@@ -244,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
}
@@ -337,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()
{
@@ -344,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 ] && {
@@ -366,6 +404,7 @@ 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;;
+24 -15
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%% 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
@@ -19,18 +19,27 @@
%%%
%%%----------------------------------------------------------------------
-record(adhoc_request, {lang,
node,
sessionid,
action,
xdata,
others}).
-record(adhoc_request,
{
lang = <<"">> :: binary(),
node = <<"">> :: binary(),
sessionid = <<"">> :: binary(),
action = <<"">> :: binary(),
xdata = false :: false | xmlel(),
others = [] :: [xmlel()]
}).
-record(adhoc_response, {lang,
node,
sessionid,
status,
defaultaction = "",
actions = [],
notes = [],
elements = []}).
-record(adhoc_response,
{
lang = <<"">> :: binary(),
node = <<"">> :: binary(),
sessionid = <<"">> :: binary(),
status :: atom(),
defaultaction = <<"">> :: binary(),
actions = [] :: [binary()],
notes = [] :: [{binary(), binary()}],
elements = [] :: [xmlel()]
}).
-type adhoc_request() :: #adhoc_request{}.
-type adhoc_response() :: #adhoc_response{}.
+31 -12
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%% 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
@@ -19,15 +19,34 @@
%%%
%%%----------------------------------------------------------------------
-record(roster, {usj,
us,
jid,
name = "",
subscription = none,
ask = none,
groups = [],
askmessage = [],
xs = []}).
-define(CT_XML,
{<<"Content-Type">>, <<"text/xml; charset=utf-8">>}).
-record(roster_version, {us,
version}).
-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).
+61
View File
@@ -0,0 +1,61 @@
%%%----------------------------------------------------------------------
%%%
%%% 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(VERSION, ejabberd_config:get_version()).
-define(MYHOSTS, ejabberd_config:get_myhosts()).
-define(MYNAME, hd(ejabberd_config:get_myhosts())).
-define(MYLANG, ejabberd_config:get_mylang()).
-define(MSGS_DIR, filename:join(["priv", "msgs"])).
-define(CONFIG_PATH, <<"ejabberd.cfg">>).
-define(LOG_PATH, <<"ejabberd.log">>).
-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).
%%-define(DBGFSM, true).
-record(scram,
{storedkey = <<"">>,
serverkey = <<"">>,
salt = <<"">>,
iterationcount = 0 :: integer()}).
-type scram() :: #scram{}.
-define(SCRAM_DEFAULT_ITERATION_COUNT, 4096).
+93
View File
@@ -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{}.
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%% 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
@@ -19,10 +19,40 @@
%%%
%%%----------------------------------------------------------------------
-record(ejabberd_commands, {name, tags = [],
desc = "", longdesc = "",
module, function,
args = [], result = rescode}).
-type aterm() :: {atom(), atype()}.
-type atype() :: integer | string | binary |
{tuple, [aterm()]} | {list, aterm()}.
-type rterm() :: {atom(), rtype()}.
-type rtype() :: integer | string | atom |
{tuple, [rterm()]} | {list, rterm()} |
rescode | restuple.
-record(ejabberd_commands,
{name :: atom(),
tags = [] :: [atom()] | '_' | '$2',
desc = "" :: string() | '_' | '$3',
longdesc = "" :: string() | '_',
module :: atom(),
function :: atom(),
args = [] :: [aterm()] | '_' | '$1' | '$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()],
desc :: string(),
longdesc :: string(),
module :: atom(),
function :: atom(),
args :: [aterm()],
result :: rterm(),
args_desc :: none | [string()],
result_desc :: none | string(),
args_example :: [any()],
result_example :: any()}.
%% @type ejabberd_commands() = #ejabberd_commands{
%% name = atom(),
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%% 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
@@ -19,21 +19,16 @@
%%%
%%%----------------------------------------------------------------------
-define(LDAP_PORT, 389).
-define(LDAPS_PORT, 636).
-record(config, {key :: any(), value :: any()}).
-record(eldap_search, {scope = wholeSubtree,
base = [],
filter,
limit = 0,
attributes = [],
types_only = false,
deref_aliases = neverDerefAliases,
timeout = 0}).
-record(local_config, {key :: any(), value :: any()}).
-type config() :: #config{}.
-type local_config() :: #local_config{}.
-record(eldap_search_result, {entries,
referrals}).
-record(eldap_entry, {object_name,
attributes}).
-record(state,
{opts = [] :: [acl:acl() | config() | local_config()],
hosts = [] :: [binary()],
override_local = false :: boolean(),
override_global = false :: boolean(),
override_acls = false :: boolean()}).
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%% 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
@@ -20,6 +20,9 @@
%%%----------------------------------------------------------------------
-define(STATUS_SUCCESS, 0).
-define(STATUS_ERROR, 1).
-define(STATUS_USAGE, 2).
-define(STATUS_BADRPC, 3).
-define(STATUS_ERROR, 1).
-define(STATUS_USAGE, 2).
-define(STATUS_BADRPC, 3).
+55
View File
@@ -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()}.
+102
View File
@@ -0,0 +1,102 @@
%%%----------------------------------------------------------------------
%%%
%%% 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(X(Name),
#xmlel{name = Name, attrs = [], children = []}).
-define(XA(Name, Attrs),
#xmlel{name = Name, attrs = Attrs, children = []}).
-define(XE(Name, Els),
#xmlel{name = Name, attrs = [], children = Els}).
-define(XAE(Name, Attrs, Els),
#xmlel{name = Name, attrs = Attrs, children = Els}).
-define(C(Text), {xmlcdata, Text}).
-define(XC(Name, Text), ?XE(Name, [?C(Text)])).
-define(XAC(Name, Attrs, Text),
?XAE(Name, Attrs, [?C(Text)])).
-define(T(Text), translate:translate(Lang, Text)).
-define(CT(Text), ?C((?T(Text)))).
-define(XCT(Name, Text), ?XC(Name, (?T(Text)))).
-define(XACT(Name, Attrs, Text),
?XAC(Name, Attrs, (?T(Text)))).
-define(LI(Els), ?XE(<<"li">>, Els)).
-define(A(URL, Els),
?XAE(<<"a">>, [{<<"href">>, URL}], Els)).
-define(AC(URL, Text), ?A(URL, [?C(Text)])).
-define(ACT(URL, Text), ?AC(URL, (?T(Text)))).
-define(P, ?X(<<"p">>)).
-define(BR, ?X(<<"br">>)).
-define(INPUT(Type, Name, Value),
?XA(<<"input">>,
[{<<"type">>, Type}, {<<"name">>, Name},
{<<"value">>, Value}])).
-define(INPUTT(Type, Name, Value),
?INPUT(Type, Name, (?T(Value)))).
-define(INPUTS(Type, Name, Value, Size),
?XA(<<"input">>,
[{<<"type">>, Type}, {<<"name">>, Name},
{<<"value">>, Value}, {<<"size">>, Size}])).
-define(INPUTST(Type, Name, Value, Size),
?INPUT(Type, Name, (?T(Value)), Size)).
-define(ACLINPUT(Text),
?XE(<<"td">>,
[?INPUT(<<"text">>, <<"value", ID/binary>>, Text)])).
-define(TEXTAREA(Name, Rows, Cols, Value),
?XAC(<<"textarea">>,
[{<<"name">>, Name}, {<<"rows">>, Rows},
{<<"cols">>, Cols}],
Value)).
-define(XRES(Text),
?XAC(<<"p">>, [{<<"class">>, <<"result">>}], Text)).
-define(XREST(Text), ?XRES((?T(Text)))).
-define(GL(Ref, Title),
?XAE(<<"div">>, [{<<"class">>, <<"guidelink">>}],
[?XAE(<<"a">>,
[{<<"href">>, <<"/admin/doc/guide.html#", Ref/binary>>},
{<<"target">>, <<"_blank">>}],
[?C(<<"[Guide: ", Title/binary, "]">>)])])).
-define(H1GL(Name, Ref, Title),
[?XC(<<"h1">>, Name), ?GL(Ref, Title)]).
+65
View File
@@ -0,0 +1,65 @@
%%%----------------------------------------------------------------------
%%%
%%% 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(LDAP_PORT, 389).
-define(LDAPS_PORT, 636).
-type scope() :: baseObject | singleLevel | wholeSubtree.
-record(eldap_search,
{scope = wholeSubtree :: scope(),
base = <<"">> :: binary(),
filter :: eldap:filter(),
limit = 0 :: non_neg_integer(),
attributes = [] :: [binary()],
types_only = false :: boolean(),
deref_aliases = neverDerefAliases :: neverDerefAliases |
derefInSearching |
derefFindingBaseObj |
derefAlways,
timeout = 0 :: non_neg_integer()}).
-record(eldap_search_result, {entries = [] :: [eldap_entry()],
referrals = [] :: list()}).
-record(eldap_entry, {object_name = <<>> :: binary(),
attributes = [] :: [{binary(), [binary()]}]}).
-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}].
-record(eldap_config, {servers = [] :: [binary()],
backups = [] :: [binary()],
tls_options = [] :: tlsopts(),
port = ?LDAP_PORT :: inet:port_number(),
dn = <<"">> :: binary(),
password = <<"">> :: binary(),
base = <<"">> :: binary(),
deref_aliases = never :: never | searching |
finding | always}).
-type eldap_config() :: #eldap_config{}.
-type eldap_search() :: #eldap_search{}.
-type eldap_entry() :: #eldap_entry{}.
+25 -10
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%% 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
@@ -19,14 +19,29 @@
%%%
%%%----------------------------------------------------------------------
-define(CT_XML, {"Content-Type", "text/xml; charset=utf-8"}).
-define(CT_PLAIN, {"Content-Type", "text/plain"}).
-define(CT_XML,
{<<"Content-Type">>, <<"text/xml; charset=utf-8">>}).
-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(CT_PLAIN,
{<<"Content-Type">>, <<"text/plain">>}).
-define(OPTIONS_HEADER, [?CT_PLAIN, ?AC_ALLOW_ORIGIN, ?AC_ALLOW_METHODS,
?AC_ALLOW_HEADERS, ?AC_MAX_AGE]).
-define(HEADER, [?CT_XML, ?AC_ALLOW_ORIGIN, ?AC_ALLOW_HEADERS]).
-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,
[?CT_XML, ?AC_ALLOW_ORIGIN, ?AC_ALLOW_HEADERS]).
+701
View File
@@ -0,0 +1,701 @@
%%%----------------------------------------------------------------------
%%%
%%% 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(NS_DISCO_ITEMS,
<<"http://jabber.org/protocol/disco#items">>).
-define(NS_DISCO_INFO,
<<"http://jabber.org/protocol/disco#info">>).
-define(NS_VCARD, <<"vcard-temp">>).
-define(NS_VCARD_UPDATE, <<"vcard-temp:x:update">>).
-define(NS_AUTH, <<"jabber:iq:auth">>).
-define(NS_AUTH_ERROR, <<"jabber:iq:auth:error">>).
-define(NS_REGISTER, <<"jabber:iq:register">>).
-define(NS_SEARCH, <<"jabber:iq:search">>).
-define(NS_ROSTER, <<"jabber:iq:roster">>).
-define(NS_ROSTER_VER,
<<"urn:xmpp:features:rosterver">>).
-define(NS_PRIVACY, <<"jabber:iq:privacy">>).
-define(NS_BLOCKING, <<"urn:xmpp:blocking">>).
-define(NS_PRIVATE, <<"jabber:iq:private">>).
-define(NS_VERSION, <<"jabber:iq:version">>).
-define(NS_TIME90, <<"jabber:iq:time">>).
-define(NS_TIME, <<"urn:xmpp:time">>).
-define(NS_LAST, <<"jabber:iq:last">>).
-define(NS_XDATA, <<"jabber:x:data">>).
-define(NS_IQDATA, <<"jabber:iq:data">>).
-define(NS_DELAY91, <<"jabber:x:delay">>).
-define(NS_DELAY, <<"urn:xmpp:delay">>).
-define(NS_EXPIRE, <<"jabber:x:expire">>).
-define(NS_EVENT, <<"jabber:x:event">>).
-define(NS_CHATSTATES,
<<"http://jabber.org/protocol/chatstates">>).
-define(NS_XCONFERENCE, <<"jabber:x:conference">>).
-define(NS_STATS,
<<"http://jabber.org/protocol/stats">>).
-define(NS_MUC, <<"http://jabber.org/protocol/muc">>).
-define(NS_MUC_USER,
<<"http://jabber.org/protocol/muc#user">>).
-define(NS_MUC_ADMIN,
<<"http://jabber.org/protocol/muc#admin">>).
-define(NS_MUC_OWNER,
<<"http://jabber.org/protocol/muc#owner">>).
-define(NS_MUC_UNIQUE,
<<"http://jabber.org/protocol/muc#unique">>).
-define(NS_PUBSUB,
<<"http://jabber.org/protocol/pubsub">>).
-define(NS_PUBSUB_EVENT,
<<"http://jabber.org/protocol/pubsub#event">>).
-define(NS_PUBSUB_META_DATA,
<<"http://jabber.org/protocol/pubsub#meta-data">>).
-define(NS_PUBSUB_OWNER,
<<"http://jabber.org/protocol/pubsub#owner">>).
-define(NS_PUBSUB_NMI,
<<"http://jabber.org/protocol/pubsub#node-meta-info">>).
-define(NS_PUBSUB_ERRORS,
<<"http://jabber.org/protocol/pubsub#errors">>).
-define(NS_PUBSUB_NODE_CONFIG,
<<"http://jabber.org/protocol/pubsub#node_config">>).
-define(NS_PUBSUB_SUB_OPTIONS,
<<"http://jabber.org/protocol/pubsub#subscribe_options">>).
-define(NS_PUBSUB_SUBSCRIBE_OPTIONS,
<<"http://jabber.org/protocol/pubsub#subscribe_options">>).
-define(NS_PUBSUB_PUBLISH_OPTIONS,
<<"http://jabber.org/protocol/pubsub#publish_options">>).
-define(NS_PUBSUB_SUB_AUTH,
<<"http://jabber.org/protocol/pubsub#subscribe_authorization">>).
-define(NS_PUBSUB_GET_PENDING,
<<"http://jabber.org/protocol/pubsub#get-pending">>).
-define(NS_COMMANDS,
<<"http://jabber.org/protocol/commands">>).
-define(NS_BYTESTREAMS,
<<"http://jabber.org/protocol/bytestreams">>).
-define(NS_ADMIN,
<<"http://jabber.org/protocol/admin">>).
-define(NS_ADMIN_ANNOUNCE,
<<"http://jabber.org/protocol/admin#announce">>).
-define(NS_ADMIN_ANNOUNCE_ALL,
<<"http://jabber.org/protocol/admin#announce-all">>).
-define(NS_ADMIN_SET_MOTD,
<<"http://jabber.org/protocol/admin#set-motd">>).
-define(NS_ADMIN_EDIT_MOTD,
<<"http://jabber.org/protocol/admin#edit-motd">>).
-define(NS_ADMIN_DELETE_MOTD,
<<"http://jabber.org/protocol/admin#delete-motd">>).
-define(NS_ADMIN_ANNOUNCE_ALLHOSTS,
<<"http://jabber.org/protocol/admin#announce-allhosts">>).
-define(NS_ADMIN_ANNOUNCE_ALL_ALLHOSTS,
<<"http://jabber.org/protocol/admin#announce-all-allhosts">>).
-define(NS_ADMIN_SET_MOTD_ALLHOSTS,
<<"http://jabber.org/protocol/admin#set-motd-allhosts">>).
-define(NS_ADMIN_EDIT_MOTD_ALLHOSTS,
<<"http://jabber.org/protocol/admin#edit-motd-allhosts">>).
-define(NS_ADMIN_DELETE_MOTD_ALLHOSTS,
<<"http://jabber.org/protocol/admin#delete-motd-allhosts">>).
-define(NS_SERVERINFO,
<<"http://jabber.org/network/serverinfo">>).
-define(NS_RSM, <<"http://jabber.org/protocol/rsm">>).
-define(NS_EJABBERD_CONFIG, <<"ejabberd:config">>).
-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">>).
-define(NS_STREAMS,
<<"urn:ietf:params:xml:ns:xmpp-streams">>).
-define(NS_TLS, <<"urn:ietf:params:xml:ns:xmpp-tls">>).
-define(NS_SASL,
<<"urn:ietf:params:xml:ns:xmpp-sasl">>).
-define(NS_SESSION,
<<"urn:ietf:params:xml:ns:xmpp-session">>).
-define(NS_BIND,
<<"urn:ietf:params:xml:ns:xmpp-bind">>).
-define(NS_FEATURE_IQAUTH,
<<"http://jabber.org/features/iq-auth">>).
-define(NS_FEATURE_IQREGISTER,
<<"http://jabber.org/features/iq-register">>).
-define(NS_FEATURE_COMPRESS,
<<"http://jabber.org/features/compress">>).
-define(NS_FEATURE_MSGOFFLINE, <<"msgoffline">>).
-define(NS_COMPRESS,
<<"http://jabber.org/protocol/compress">>).
-define(NS_CAPS, <<"http://jabber.org/protocol/caps">>).
-define(NS_SHIM, <<"http://jabber.org/protocol/shim">>).
-define(NS_ADDRESS,
<<"http://jabber.org/protocol/address">>).
-define(NS_OOB, <<"jabber:x:oob">>).
-define(NS_CAPTCHA, <<"urn:xmpp:captcha">>).
-define(NS_MEDIA, <<"urn:xmpp:media-element">>).
-define(NS_BOB, <<"urn:xmpp:bob">>).
-include("xml.hrl").
-define(STANZA_ERROR(Code, Type, Condition),
#xmlel{name = <<"error">>,
attrs = [{<<"code">>, Code}, {<<"type">>, Type}],
children =
[#xmlel{name = Condition,
attrs = [{<<"xmlns">>, ?NS_STANZAS}],
children = []}]}).
-define(ERR_BAD_FORMAT,
?STANZA_ERROR(<<"406">>, <<"modify">>,
<<"bad-format">>)).
-define(ERR_BAD_REQUEST,
?STANZA_ERROR(<<"400">>, <<"modify">>,
<<"bad-request">>)).
-define(ERR_CONFLICT,
?STANZA_ERROR(<<"409">>, <<"cancel">>, <<"conflict">>)).
-define(ERR_FEATURE_NOT_IMPLEMENTED,
?STANZA_ERROR(<<"501">>, <<"cancel">>,
<<"feature-not-implemented">>)).
-define(ERR_FORBIDDEN,
?STANZA_ERROR(<<"403">>, <<"auth">>, <<"forbidden">>)).
-define(ERR_GONE,
?STANZA_ERROR(<<"302">>, <<"modify">>, <<"gone">>)).
-define(ERR_INTERNAL_SERVER_ERROR,
?STANZA_ERROR(<<"500">>, <<"wait">>,
<<"internal-server-error">>)).
-define(ERR_ITEM_NOT_FOUND,
?STANZA_ERROR(<<"404">>, <<"cancel">>,
<<"item-not-found">>)).
-define(ERR_JID_MALFORMED,
?STANZA_ERROR(<<"400">>, <<"modify">>,
<<"jid-malformed">>)).
-define(ERR_NOT_ACCEPTABLE,
?STANZA_ERROR(<<"406">>, <<"modify">>,
<<"not-acceptable">>)).
-define(ERR_NOT_ALLOWED,
?STANZA_ERROR(<<"405">>, <<"cancel">>,
<<"not-allowed">>)).
-define(ERR_NOT_AUTHORIZED,
?STANZA_ERROR(<<"401">>, <<"auth">>,
<<"not-authorized">>)).
-define(ERR_PAYMENT_REQUIRED,
?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">>)).
-define(ERR_REDIRECT,
?STANZA_ERROR(<<"302">>, <<"modify">>, <<"redirect">>)).
-define(ERR_REGISTRATION_REQUIRED,
?STANZA_ERROR(<<"407">>, <<"auth">>,
<<"registration-required">>)).
-define(ERR_REMOTE_SERVER_NOT_FOUND,
?STANZA_ERROR(<<"404">>, <<"cancel">>,
<<"remote-server-not-found">>)).
-define(ERR_REMOTE_SERVER_TIMEOUT,
?STANZA_ERROR(<<"504">>, <<"wait">>,
<<"remote-server-timeout">>)).
-define(ERR_RESOURCE_CONSTRAINT,
?STANZA_ERROR(<<"500">>, <<"wait">>,
<<"resource-constraint">>)).
-define(ERR_SERVICE_UNAVAILABLE,
?STANZA_ERROR(<<"503">>, <<"cancel">>,
<<"service-unavailable">>)).
-define(ERR_SUBSCRIPTION_REQUIRED,
?STANZA_ERROR(<<"407">>, <<"auth">>,
<<"subscription-required">>)).
-define(ERR_UNEXPECTED_REQUEST,
?STANZA_ERROR(<<"400">>, <<"wait">>,
<<"unexpected-request">>)).
-define(ERR_UNEXPECTED_REQUEST_CANCEL,
?STANZA_ERROR(<<"401">>, <<"cancel">>,
<<"unexpected-request">>)).
%-define(ERR_,
% ?STANZA_ERROR("", "", "")).
-define(STANZA_ERRORT(Code, Type, Condition, Lang,
Text),
#xmlel{name = <<"error">>,
attrs = [{<<"code">>, Code}, {<<"type">>, Type}],
children =
[#xmlel{name = Condition,
attrs = [{<<"xmlns">>, ?NS_STANZAS}], children = []},
#xmlel{name = <<"text">>,
attrs = [{<<"xmlns">>, ?NS_STANZAS}],
children =
[{xmlcdata,
translate:translate(Lang, Text)}]}]}).
-define(ERRT_BAD_FORMAT(Lang, Text),
?STANZA_ERRORT(<<"406">>, <<"modify">>,
<<"bad-format">>, Lang, Text)).
-define(ERRT_BAD_REQUEST(Lang, Text),
?STANZA_ERRORT(<<"400">>, <<"modify">>,
<<"bad-request">>, Lang, Text)).
-define(ERRT_CONFLICT(Lang, Text),
?STANZA_ERRORT(<<"409">>, <<"cancel">>, <<"conflict">>,
Lang, Text)).
-define(ERRT_FEATURE_NOT_IMPLEMENTED(Lang, Text),
?STANZA_ERRORT(<<"501">>, <<"cancel">>,
<<"feature-not-implemented">>, Lang, Text)).
-define(ERRT_FORBIDDEN(Lang, Text),
?STANZA_ERRORT(<<"403">>, <<"auth">>, <<"forbidden">>,
Lang, Text)).
-define(ERRT_GONE(Lang, Text),
?STANZA_ERRORT(<<"302">>, <<"modify">>, <<"gone">>,
Lang, Text)).
-define(ERRT_INTERNAL_SERVER_ERROR(Lang, Text),
?STANZA_ERRORT(<<"500">>, <<"wait">>,
<<"internal-server-error">>, Lang, Text)).
-define(ERRT_ITEM_NOT_FOUND(Lang, Text),
?STANZA_ERRORT(<<"404">>, <<"cancel">>,
<<"item-not-found">>, Lang, Text)).
-define(ERRT_JID_MALFORMED(Lang, Text),
?STANZA_ERRORT(<<"400">>, <<"modify">>,
<<"jid-malformed">>, Lang, Text)).
-define(ERRT_NOT_ACCEPTABLE(Lang, Text),
?STANZA_ERRORT(<<"406">>, <<"modify">>,
<<"not-acceptable">>, Lang, Text)).
-define(ERRT_NOT_ALLOWED(Lang, Text),
?STANZA_ERRORT(<<"405">>, <<"cancel">>,
<<"not-allowed">>, Lang, Text)).
-define(ERRT_NOT_AUTHORIZED(Lang, Text),
?STANZA_ERRORT(<<"401">>, <<"auth">>,
<<"not-authorized">>, Lang, Text)).
-define(ERRT_PAYMENT_REQUIRED(Lang, Text),
?STANZA_ERRORT(<<"402">>, <<"auth">>,
<<"payment-required">>, Lang, Text)).
-define(ERRT_RECIPIENT_UNAVAILABLE(Lang, Text),
?STANZA_ERRORT(<<"404">>, <<"wait">>,
<<"recipient-unavailable">>, Lang, Text)).
-define(ERRT_REDIRECT(Lang, Text),
?STANZA_ERRORT(<<"302">>, <<"modify">>, <<"redirect">>,
Lang, Text)).
-define(ERRT_REGISTRATION_REQUIRED(Lang, Text),
?STANZA_ERRORT(<<"407">>, <<"auth">>,
<<"registration-required">>, Lang, Text)).
-define(ERRT_REMOTE_SERVER_NOT_FOUND(Lang, Text),
?STANZA_ERRORT(<<"404">>, <<"cancel">>,
<<"remote-server-not-found">>, Lang, Text)).
-define(ERRT_REMOTE_SERVER_TIMEOUT(Lang, Text),
?STANZA_ERRORT(<<"504">>, <<"wait">>,
<<"remote-server-timeout">>, Lang, Text)).
-define(ERRT_RESOURCE_CONSTRAINT(Lang, Text),
?STANZA_ERRORT(<<"500">>, <<"wait">>,
<<"resource-constraint">>, Lang, Text)).
-define(ERRT_SERVICE_UNAVAILABLE(Lang, Text),
?STANZA_ERRORT(<<"503">>, <<"cancel">>,
<<"service-unavailable">>, Lang, Text)).
-define(ERRT_SUBSCRIPTION_REQUIRED(Lang, Text),
?STANZA_ERRORT(<<"407">>, <<"auth">>,
<<"subscription-required">>, Lang, Text)).
-define(ERRT_UNEXPECTED_REQUEST(Lang, Text),
?STANZA_ERRORT(<<"400">>, <<"wait">>,
<<"unexpected-request">>, Lang, Text)).
-define(ERR_AUTH_NO_RESOURCE_PROVIDED(Lang),
?ERRT_NOT_ACCEPTABLE(Lang, <<"No resource provided">>)).
-define(ERR_AUTH_BAD_RESOURCE_FORMAT(Lang),
?ERRT_NOT_ACCEPTABLE(Lang,
<<"Illegal resource format">>)).
-define(ERR_AUTH_RESOURCE_CONFLICT(Lang),
?ERRT_CONFLICT(Lang, <<"Resource conflict">>)).
-define(STREAM_ERROR(Condition, Cdata),
#xmlel{name = <<"stream:error">>, attrs = [],
children =
[#xmlel{name = Condition,
attrs = [{<<"xmlns">>, ?NS_STREAMS}],
children = [{xmlcdata, Cdata}]}]}).
-define(SERR_BAD_FORMAT,
?STREAM_ERROR(<<"bad-format">>, <<"">>)).
-define(SERR_BAD_NAMESPACE_PREFIX,
?STREAM_ERROR(<<"bad-namespace-prefix">>, <<"">>)).
-define(SERR_CONFLICT,
?STREAM_ERROR(<<"conflict">>, <<"">>)).
-define(SERR_CONNECTION_TIMEOUT,
?STREAM_ERROR(<<"connection-timeout">>, <<"">>)).
-define(SERR_HOST_GONE,
?STREAM_ERROR(<<"host-gone">>, <<"">>)).
-define(SERR_HOST_UNKNOWN,
?STREAM_ERROR(<<"host-unknown">>, <<"">>)).
-define(SERR_IMPROPER_ADDRESSING,
?STREAM_ERROR(<<"improper-addressing">>, <<"">>)).
-define(SERR_INTERNAL_SERVER_ERROR,
?STREAM_ERROR(<<"internal-server-error">>, <<"">>)).
-define(SERR_INVALID_FROM,
?STREAM_ERROR(<<"invalid-from">>, <<"">>)).
-define(SERR_INVALID_ID,
?STREAM_ERROR(<<"invalid-id">>, <<"">>)).
-define(SERR_INVALID_NAMESPACE,
?STREAM_ERROR(<<"invalid-namespace">>, <<"">>)).
-define(SERR_INVALID_XML,
?STREAM_ERROR(<<"invalid-xml">>, <<"">>)).
-define(SERR_NOT_AUTHORIZED,
?STREAM_ERROR(<<"not-authorized">>, <<"">>)).
-define(SERR_POLICY_VIOLATION,
?STREAM_ERROR(<<"policy-violation">>, <<"">>)).
-define(SERR_REMOTE_CONNECTION_FAILED,
?STREAM_ERROR(<<"remote-connection-failed">>, <<"">>)).
-define(SERR_RESOURSE_CONSTRAINT,
?STREAM_ERROR(<<"resource-constraint">>, <<"">>)).
-define(SERR_RESTRICTED_XML,
?STREAM_ERROR(<<"restricted-xml">>, <<"">>)).
-define(SERR_SEE_OTHER_HOST(Host),
?STREAM_ERROR(<<"see-other-host">>, Host)).
-define(SERR_SYSTEM_SHUTDOWN,
?STREAM_ERROR(<<"system-shutdown">>, <<"">>)).
-define(SERR_UNSUPPORTED_ENCODING,
?STREAM_ERROR(<<"unsupported-encoding">>, <<"">>)).
-define(SERR_UNSUPPORTED_STANZA_TYPE,
?STREAM_ERROR(<<"unsupported-stanza-type">>, <<"">>)).
-define(SERR_UNSUPPORTED_VERSION,
?STREAM_ERROR(<<"unsupported-version">>, <<"">>)).
-define(SERR_XML_NOT_WELL_FORMED,
?STREAM_ERROR(<<"xml-not-well-formed">>, <<"">>)).
%-define(SERR_,
% ?STREAM_ERROR("", "")).
-define(STREAM_ERRORT(Condition, Cdata, Lang, Text),
#xmlel{name = <<"stream:error">>, attrs = [],
children =
[#xmlel{name = Condition,
attrs = [{<<"xmlns">>, ?NS_STREAMS}],
children = [{xmlcdata, Cdata}]},
#xmlel{name = <<"text">>,
attrs =
[{<<"xml:lang">>, Lang},
{<<"xmlns">>, ?NS_STREAMS}],
children =
[{xmlcdata,
translate:translate(Lang, Text)}]}]}).
-define(SERRT_BAD_FORMAT(Lang, Text),
?STREAM_ERRORT(<<"bad-format">>, <<"">>, Lang, Text)).
-define(SERRT_BAD_NAMESPACE_PREFIX(Lang, Text),
?STREAM_ERRORT(<<"bad-namespace-prefix">>, <<"">>, Lang,
Text)).
-define(SERRT_CONFLICT(Lang, Text),
?STREAM_ERRORT(<<"conflict">>, <<"">>, Lang, Text)).
-define(SERRT_CONNECTION_TIMEOUT(Lang, Text),
?STREAM_ERRORT(<<"connection-timeout">>, <<"">>, Lang,
Text)).
-define(SERRT_HOST_GONE(Lang, Text),
?STREAM_ERRORT(<<"host-gone">>, <<"">>, Lang, Text)).
-define(SERRT_HOST_UNKNOWN(Lang, Text),
?STREAM_ERRORT(<<"host-unknown">>, <<"">>, Lang, Text)).
-define(SERRT_IMPROPER_ADDRESSING(Lang, Text),
?STREAM_ERRORT(<<"improper-addressing">>, <<"">>, Lang,
Text)).
-define(SERRT_INTERNAL_SERVER_ERROR(Lang, Text),
?STREAM_ERRORT(<<"internal-server-error">>, <<"">>,
Lang, Text)).
-define(SERRT_INVALID_FROM(Lang, Text),
?STREAM_ERRORT(<<"invalid-from">>, <<"">>, Lang, Text)).
-define(SERRT_INVALID_ID(Lang, Text),
?STREAM_ERRORT(<<"invalid-id">>, <<"">>, Lang, Text)).
-define(SERRT_INVALID_NAMESPACE(Lang, Text),
?STREAM_ERRORT(<<"invalid-namespace">>, <<"">>, Lang,
Text)).
-define(SERRT_INVALID_XML(Lang, Text),
?STREAM_ERRORT(<<"invalid-xml">>, <<"">>, Lang, Text)).
-define(SERRT_NOT_AUTHORIZED(Lang, Text),
?STREAM_ERRORT(<<"not-authorized">>, <<"">>, Lang,
Text)).
-define(SERRT_POLICY_VIOLATION(Lang, Text),
?STREAM_ERRORT(<<"policy-violation">>, <<"">>, Lang,
Text)).
-define(SERRT_REMOTE_CONNECTION_FAILED(Lang, Text),
?STREAM_ERRORT(<<"remote-connection-failed">>, <<"">>,
Lang, Text)).
-define(SERRT_RESOURSE_CONSTRAINT(Lang, Text),
?STREAM_ERRORT(<<"resource-constraint">>, <<"">>, Lang,
Text)).
-define(SERRT_RESTRICTED_XML(Lang, Text),
?STREAM_ERRORT(<<"restricted-xml">>, <<"">>, Lang,
Text)).
-define(SERRT_SEE_OTHER_HOST(Host, Lang, Text),
?STREAM_ERRORT(<<"see-other-host">>, Host, Lang, Text)).
-define(SERRT_SYSTEM_SHUTDOWN(Lang, Text),
?STREAM_ERRORT(<<"system-shutdown">>, <<"">>, Lang,
Text)).
-define(SERRT_UNSUPPORTED_ENCODING(Lang, Text),
?STREAM_ERRORT(<<"unsupported-encoding">>, <<"">>, Lang,
Text)).
-define(SERRT_UNSUPPORTED_STANZA_TYPE(Lang, Text),
?STREAM_ERRORT(<<"unsupported-stanza-type">>, <<"">>,
Lang, Text)).
-define(SERRT_UNSUPPORTED_VERSION(Lang, Text),
?STREAM_ERRORT(<<"unsupported-version">>, <<"">>, Lang,
Text)).
-define(SERRT_XML_NOT_WELL_FORMED(Lang, Text),
?STREAM_ERRORT(<<"xml-not-well-formed">>, <<"">>, Lang,
Text)).
-record(jid, {user = <<"">> :: binary(),
server = <<"">> :: binary(),
resource = <<"">> :: binary(),
luser = <<"">> :: binary(),
lserver = <<"">> :: binary(),
lresource = <<"">> :: binary()}).
-type(jid() :: #jid{}).
-type(ljid() :: {binary(), binary(), binary()}).
-record(iq, {id = <<"">> :: binary(),
type = get :: get | set | result | error,
xmlns = <<"">> :: binary(),
lang = <<"">> :: binary(),
sub_el = #xmlel{} :: xmlel() | [xmlel()]}).
-type(iq_get()
:: #iq{
id :: binary(),
type :: get,
xmlns :: binary(),
lang :: binary(),
sub_el :: xmlel()
}
).
-type(iq_set()
:: #iq{
id :: binary(),
type :: set,
xmlns :: binary(),
lang :: binary(),
sub_el :: xmlel()
}
).
-type iq_request() :: iq_get() | iq_set().
-type(iq_result()
:: #iq{
id :: binary(),
type :: result,
xmlns :: binary(),
lang :: binary(),
sub_el :: [xmlel()]
}
).
-type(iq_error()
:: #iq{
id :: binary(),
type :: error,
xmlns :: binary(),
lang :: binary(),
sub_el :: [xmlel()]
}
).
-type iq_reply() :: iq_result() | iq_error() .
-type(iq() :: iq_request() | iq_reply()).
-record(rsm_in, {max :: integer(),
direction :: before | aft,
id :: binary(),
index :: integer()}).
-record(rsm_out, {count :: integer(),
index :: integer(),
first :: binary(),
last :: binary()}).
-type(rsm_in() :: #rsm_in{}).
-type(rsm_out() :: #rsm_out{}).
-type broadcast() :: {broadcast, broadcast_data()}.
-type broadcast_data() ::
{rebind, pid(), binary()} | %% ejabberd_c2s
{item, ljid(), mod_roster:subscription()} | %% mod_roster/mod_shared_roster
{exit, binary()} | %% mod_roster/mod_shared_roster
{privacy_list, mod_privacy:userlist(), binary()} | %% mod_privacy
{blocking, unblock_all | {block | unblock, [ljid()]}}. %% mod_blocking
-record(xmlelement, {name = "" :: string(),
attrs = [] :: [{string(), string()}],
children = [] :: [{xmlcdata, iodata()} | xmlelement()]}).
-type xmlelement() :: #xmlelement{}.
+1
View File
@@ -0,0 +1 @@
-define(IS_VALID, true).
+14 -15
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%% 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
@@ -18,20 +18,19 @@
%%% 02111-1307 USA
%%%
%%%----------------------------------------------------------------------
-define(PRINT(Format, Args), io:format(Format, Args)).
-record(privacy, {us,
default = none,
lists = []}).
-define(DEBUG(Format, Args),
ejabberd_logger:debug_msg(?MODULE, ?LINE, Format, Args)).
-record(listitem, {type = none,
value = none,
action,
order,
match_all = false,
match_iq = false,
match_message = false,
match_presence_in = false,
match_presence_out = false
}).
-define(INFO_MSG(Format, Args),
ejabberd_logger:info_msg(?MODULE, ?LINE, Format, Args)).
-record(userlist, {name = none, list = [], needdb = false }).
-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)).
+117
View File
@@ -0,0 +1,117 @@
%%%----------------------------------------------------------------------
%%%
%%% 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(MAX_USERS_DEFAULT, 200).
-define(SETS, gb_sets).
-define(DICT, dict).
-record(lqueue,
{
queue :: queue(),
len :: integer(),
max :: integer()
}).
-type lqueue() :: #lqueue{}.
-record(config,
{
title = <<"">> :: binary(),
description = <<"">> :: binary(),
allow_change_subj = true :: boolean(),
allow_query_users = true :: boolean(),
allow_private_messages = true :: boolean(),
allow_private_messages_from_visitors = anyone :: anyone | moderators | nobody ,
allow_visitor_status = true :: boolean(),
allow_visitor_nickchange = true :: boolean(),
public = true :: boolean(),
public_list = true :: boolean(),
persistent = false :: boolean(),
moderated = true :: boolean(),
captcha_protected = false :: boolean(),
members_by_default = true :: boolean(),
members_only = false :: boolean(),
allow_user_invites = false :: boolean(),
password_protected = false :: boolean(),
password = <<"">> :: binary(),
anonymous = true :: boolean(),
allow_voice_requests = true :: boolean(),
voice_request_min_interval = 1800 :: non_neg_integer(),
max_users = ?MAX_USERS_DEFAULT :: non_neg_integer() | none,
logging = false :: boolean(),
captcha_whitelist = (?SETS):empty() :: gb_set()
}).
-type config() :: #config{}.
-type role() :: moderator | participant | visitor | none.
-record(user,
{
jid :: jid(),
nick :: binary(),
role :: role(),
last_presence :: xmlel()
}).
-record(activity,
{
message_time = 0 :: integer(),
presence_time = 0 :: integer(),
message_shaper :: shaper:shaper(),
presence_shaper :: shaper:shaper(),
message :: xmlel(),
presence :: {binary(), xmlel()}
}).
-record(state,
{
room = <<"">> :: binary(),
host = <<"">> :: binary(),
server_host = <<"">> :: binary(),
access = {none,none,none,none} :: {atom(), atom(), atom(), atom()},
jid = #jid{} :: jid(),
config = #config{} :: config(),
users = (?DICT):new() :: dict(),
last_voice_request_time = treap:empty() :: treap:treap(),
robots = (?DICT):new() :: dict(),
nicks = (?DICT):new() :: dict(),
affiliations = (?DICT):new() :: dict(),
history :: lqueue(),
persist_history = false :: boolean(),
subject = <<"">> :: binary(),
subject_author = <<"">> :: binary(),
just_created = false :: boolean(),
activity = treap:empty() :: treap:treap(),
room_shaper = none :: shaper:shaper(),
room_queue = queue:new() :: queue()
}).
-record(muc_online_users, {us = {<<>>, <<>>} :: {binary(), binary()},
resource = <<>> :: binary() | '_',
room = <<>> :: binary() | '_',
host = <<>> :: binary() | '_'}).
-type muc_online_users() :: #muc_online_users{}.
-type muc_room_state() :: #state{}.
+46
View File
@@ -0,0 +1,46 @@
%%%----------------------------------------------------------------------
%%%
%%% 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(mod_privacy_hrl, true).
-record(privacy, {us = {<<"">>, <<"">>} :: {binary(), binary()},
default = none :: none | binary(),
lists = [] :: [{binary(), [listitem()]}]}).
-record(listitem, {type = none :: none | jid | group | subscription,
value = none :: none | both | from | to | ljid() | binary(),
action = allow :: allow | deny,
order = 0 :: integer(),
match_all = false :: boolean(),
match_iq = false :: boolean(),
match_message = false :: boolean(),
match_presence_in = false :: boolean(),
match_presence_out = false :: boolean()}).
-type listitem() :: #listitem{}.
-record(userlist, {name = none :: none | binary(),
list = [] :: [listitem()],
needdb = false :: boolean()}).
-type userlist() :: #userlist{}.
-export_type([userlist/0]).
@@ -2,7 +2,7 @@
%%% RFC 1928 constants.
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%% 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
@@ -21,41 +21,48 @@
%%%
%%%----------------------------------------------------------------------
%% Version
-define(VERSION_5, 5).
%% Authentication methods
-define(AUTH_ANONYMOUS, 0).
-define(AUTH_GSSAPI, 1).
-define(AUTH_PLAIN, 2).
-define(AUTH_NO_METHODS, 16#FF).
%% Address Type
-define(AUTH_GSSAPI, 1).
-define(AUTH_PLAIN, 2).
-define(AUTH_NO_METHODS, 255).
-define(ATYP_IPV4, 1).
-define(ATYP_DOMAINNAME, 3).
-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).
-define(ERR_NOT_ALLOWED, 2).
-define(ERR_NETWORK_UNREACHABLE, 3).
-define(ERR_HOST_UNREACHABLE, 4).
-define(ERR_CONNECTION_REFUSED, 5).
-define(ERR_TTL_EXPIRED, 6).
-define(ERR_COMMAND_NOT_SUPPORTED, 7).
-define(ERR_ADDRESS_TYPE_NOT_SUPPORTED, 8).
%% RFC 1928 defined timeout.
-define(SOCKS5_REPLY_TIMEOUT, 10000).
-record(s5_request, {
rsv = 0,
cmd,
sha1
}).
-record(s5_request, {rsv = 0 :: integer(),
cmd = connect :: connect | udp,
sha1 = <<"">> :: binary()}).
+42
View File
@@ -0,0 +1,42 @@
%%%----------------------------------------------------------------------
%%%
%%% 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(roster,
{
usj = {<<>>, <<>>, {<<>>, <<>>, <<>>}} :: {binary(), binary(), ljid()} | '_',
us = {<<>>, <<>>} :: {binary(), binary()} | '_',
jid = {<<>>, <<>>, <<>>} :: ljid(),
name = <<>> :: binary() | '_',
subscription = none :: subscription() | '_',
ask = none :: ask() | '_',
groups = [] :: [binary()] | '_',
askmessage = <<"">> :: binary() | '_',
xs = [] :: [xmlel()] | '_'
}).
-record(roster_version,
{
us = {<<>>, <<>>} :: {binary(), binary()},
version = <<>> :: binary()
}).
-type ask() :: none | in | out | both | subscribe | unsubscribe.
-type subscription() :: none | both | from | to | remove.
+207
View File
@@ -0,0 +1,207 @@
%%% ====================================================================
%%% ``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
%%%
%%% This file contains pubsub types definition.
%%% ====================================================================
-define(ERR_EXTENDED(E, C),
mod_pubsub:extended_error(E, C)).
-define(MAXITEMS, 10).
-define(MAX_PAYLOAD_SIZE, 60000).
%% -------------------------------
%% Pubsub types
-type(hostPubsub() :: binary()).
%% <p><tt>hostPubsub</tt> is the name of the PubSub service. For example, it can be
%% <tt>"pubsub.localhost"</tt>.</p>
-type(hostPEP() :: {binary(), binary(), <<>>}).
%% @type hostPEP() = {User, Server, Resource}
%% User = string()
%% Server = string()
%% Resource = [].
%% <p>For example, it can be :
%% ```{"bob", "example.org", []}'''.</p>
-type(host() :: hostPubsub() | hostPEP()).
%% @type host() = hostPubsub() | hostPEP().
-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:
%% ```<<"/home/localhost/user">>'''</p>
-type(nodeIdx() :: pos_integer()).
%% @type nodeIdx() = integer().
-type(itemId() :: binary()).
%% @type itemId() = string().
-type(subId() :: binary()).
%% @type subId() = string().
%% @type payload() = [#xmlelement{} | #xmlcdata{}].
%% @type stanzaError() = #xmlelement{}.
%% Example:
%% ```{xmlelement, "error",
%% [{"code", Code}, {"type", Type}],
%% [{xmlelement, Condition, [{"xmlns", ?NS_STANZAS}], []}]}'''
%% @type pubsubIQResponse() = #xmlelement{}.
%% Example:
%% ```{xmlelement, "pubsub",
%% [{"xmlns", ?NS_PUBSUB_EVENT}],
%% [{xmlelement, "affiliations", [],
%% []}]}'''
-type(nodeOption() ::
{Option::atom(),
Value::binary() | [binary()] | boolean() | non_neg_integer()
}).
-type(nodeOptions() :: [NodeOption::mod_pubsub:nodeOption(),...]).
%% @type nodeOption() = {Option, Value}
%% Option = atom()
%% Value = term().
%% Example:
%% ```{deliver_payloads, true}'''
-type(subOption() ::
{Option::atom(),
Value::binary() | [binary()] | boolean()
}).
-type(subOptions() :: [SubOption::mod_pubsub:subOption(),...]).
%% @type nodeType() = string().
%% <p>The <tt>nodeType</tt> is a string containing the name of the PubSub
%% plugin to use to manage a given node. For example, it can be
%% <tt>"flat"</tt>, <tt>"hometree"</tt> or <tt>"blog"</tt>.</p>
%% @type jid() = {jid, User, Server, Resource, LUser, LServer, LResource}
%% User = string()
%% Server = string()
%% Resource = string()
%% LUser = string()
%% LServer = string()
%% LResource = string().
%-type(ljid() :: {binary(), binary(), binary()}).
%% @type ljid() = {User, Server, Resource}
%% User = string()
%% Server = string()
%% Resource = string().
-type(affiliation() :: 'none'
| 'owner'
| 'publisher'
%| 'publish-only'
| 'member'
| 'outcast'
).
%% @type affiliation() = 'none' | 'owner' | 'publisher' | 'publish-only' | 'member' | 'outcast'.
-type(subscription() :: 'none'
| 'pending'
| 'unconfigured'
| 'subscribed'
).
%% @type subscription() = 'none' | 'pending' | 'unconfigured' | 'subscribed'.
-type(accessModel() :: 'open'
| 'presence'
| 'roster'
| 'authorize'
| 'whitelist'
).
%% @type accessModel() = 'open' | 'presence' | 'roster' | 'authorize' | 'whitelist'.
-type(publishModel() :: 'publishers'
| 'subscribers'
| 'open'
).
-record(pubsub_index,
{
index :: atom(),
last :: mod_pubsub:nodeIdx(),
free :: [mod_pubsub:nodeIdx()]
}).
-record(pubsub_node,
{
nodeid ,%:: {Host::mod_pubsub:host(), NodeId::mod_pubsub:nodeId()},
id ,%:: mod_pubsub:nodeIdx(),
parents = [] ,%:: [Parent_NodeId::mod_pubsub:nodeId()],
type = <<"flat">> ,%:: binary(),
owners = [] ,%:: [Owner::ljid(),...],
options = [] %:: mod_pubsub:nodeOptions()
}).
%-record(pubsub_state,
% {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()}]
}).
%-record(pubsub_item,
% {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()
}).
%-record(pubsub_subscription, {subid, options}).
-record(pubsub_subscription,
{
subid ,%:: mod_pubsub:subId(),
options %:: [] | mod_pubsub:subOptions()
}).
%-record(pubsub_last_item,
% {nodeid, itemid, creation, payload}).
-record(pubsub_last_item,
{
nodeid ,%:: mod_pubsub:nodeIdx(),
itemid ,%:: mod_pubsub:itemId(),
creation ,%:: {erlang:timestamp(), ljid()},
payload %:: mod_pubsub:payload()
}).
View File
View File
+685
View File
@@ -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).
+863
View File
@@ -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.
+310
View File
@@ -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">>}].
+101
View File
@@ -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
+147
View File
@@ -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
+904
View File
@@ -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]).
+570
View File
@@ -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.
+113
View File
@@ -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
+685
View File
@@ -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.
+108
View File
@@ -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)]).
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
File diff suppressed because it is too large Load Diff
View File

Some files were not shown because too many files have changed in this diff Show More