Compare commits

..

273 Commits

Author SHA1 Message Date
Paweł Chmielowski 28186ddf19 Document auth_scram_hash option 2020-12-15 15:40:16 +01:00
Paweł Chmielowski 8dfe7e977a Bump version in mix.exs 2020-12-15 15:27:16 +01:00
Paweł Chmielowski b345632a9a Update changelog 2020-12-15 15:26:23 +01:00
Paweł Chmielowski 34e615d854 Update deps in mix 2020-12-15 15:24:57 +01:00
Paweł Chmielowski d8d9ef32ad Make anonymous auth not override sasl mechaninsm offered by other modules
This stop overriding store_type when anonymous is enabled with other
auth modules, we don't really need that since anonymous is not taking
passwords anyway, and this was disabling scram mechanisms.

This fixes issue #2803.
2020-12-14 16:42:14 +01:00
Paweł Chmielowski a9ed26e484 Fix getting age of newly created rooms in rooms_unused_* 2020-12-14 09:47:25 +01:00
Pouriya a76531b90b feat: add hook to check decoded JWT after success authentication (#3446) 2020-12-14 08:14:58 +01:00
Paweł Chmielowski d64e453364 Update deps 2020-12-10 15:00:46 +01:00
Paweł Chmielowski af9d642a71 Improve auth_mnesia:transform 2020-12-10 14:02:28 +01:00
Paweł Chmielowski 6a659d7475 Improve handling of old scram data in auth_mnesia 2020-12-10 14:00:13 +01:00
Paweł Chmielowski 7da81249f8 Update xmpp once more 2020-12-10 13:22:32 +01:00
Paweł Chmielowski 8214a4fa79 Update xmpp 2020-12-10 12:41:26 +01:00
Paweł Chmielowski e048bc6712 Update deps to point to tags 2020-12-08 15:11:09 +01:00
Paweł Chmielowski e5cad9be65 Add hash to scramed password stored in mnesia by earlier version 2020-12-08 12:18:03 +01:00
Paweł Chmielowski 1dc0ecd1e9 Allow to use different hash for storing scram passwords 2020-12-08 12:06:52 +01:00
Paweł Chmielowski 0c09599d7b Normalize names passed to destroy_room 2020-12-08 09:19:29 +01:00
badlop e95ae66d3c Merge pull request #3435 from fdie/fix_odbc_binary_errors
also convert embedded errors to binary
2020-12-04 13:48:13 +01:00
Paweł Chmielowski 5f9d480f6a Simplify updating disk room options in set_room_affiliation 2020-12-04 13:06:53 +01:00
Paweł Chmielowski d34227cae1 Use specialized upsert with mysql 2020-12-04 13:03:55 +01:00
Paweł Chmielowski 72867f8d1e Fix more places that needed changes after scram.erl api modifications 2020-12-04 09:20:59 +01:00
Frank Diebolt 8f04491a4d also convert embedded errors to binary 2020-12-03 19:56:58 +01:00
Paweł Chmielowski 0371b0f664 Add support for SCRAM-SHA-{256,512}-{PLUS} authentication 2020-12-03 15:07:09 +01:00
Paweł Chmielowski 02cc212f16 Fix typo in last commit 2020-12-01 15:39:17 +01:00
Paweł Chmielowski 0fe64674ee Make decide room better handle rooms that were just hibernated 2020-12-01 15:30:23 +01:00
Paweł Chmielowski e937ff62fe Handle unix sockets in misc:ip_to_list 2020-12-01 15:29:58 +01:00
Badlop d75d69d5d5 Trigger user_send_packet when send_stanza API is called (#3431) 2020-12-01 13:14:24 +01:00
badlop f48f9fee2e Merge pull request #3429 from mtdcr/systemd-foreground
Let systemd start ejabberd in foreground
2020-11-25 13:05:14 +01:00
Andreas Oberritter 5c6ffaafd6 Let systemd start ejabberd in foreground
Daemons started by systemd shouldn't fork into the background if
possible, because if multiple forked processes exist, systemd has
a hard time determining the main process ID.

In a memory constrained environment, the OOM killer may cause
ejabberd to exit without any trace. Because epmd keeps running,
systemd wouldn't notice the error condition, and as a result it
won't restart the server.

With ejabberd running in foreground, systemd is able to obtain the
correct exit code (137 in this case, instead of 0) and schedules a
restart. The administrator can then see what happend by looking at
systemctl status ejabberd.
2020-11-19 20:43:51 +01:00
Badlop 3581d90d9d Provide name when pushing new roster item in shared roster group (#3427) 2020-11-19 17:07:23 +01:00
Paweł Chmielowski 9e1f3862cb Fix room_unused_destroy on hibernated rooms 2020-11-19 09:31:14 +01:00
Paweł Chmielowski c2a3f037bb Update muc_room just_created timestamp when message is received
This together with last history message is used by room_unused_* command
to determine for how long room was not used, this change allow us to skip
checking history, and works even when history is disabled.
2020-11-18 17:14:28 +01:00
Paweł Chmielowski bf1aacefcb We don't use persistent field in decide_room 2020-11-18 16:49:43 +01:00
Paweł Chmielowski e306cb0797 Fix logic that determines room age when history_size=0 2020-11-18 16:49:43 +01:00
badlop 1c6221d8a0 Merge pull request #3402 from nosnilmot/docker-fixes
Fix docker DB initialization
2020-11-17 16:48:13 +01:00
Paweł Chmielowski 2e8023158d Allow room_unused_list/destroy work on hibernated rooms
This required adding hibernation time to data stored for room to be able
determine how old was a room, rooms that aren't stored with that
information will use node start time as timestamp for that.
2020-11-16 16:05:16 +01:00
badlop ff98cb4e15 Merge pull request #3399 from nosnilmot/redis3-configure_deps
Improve rebar3 configure-deps plugin output
2020-11-13 17:04:22 +01:00
badlop 0f01019e06 Merge pull request #3395 from nosnilmot/rebar3
rebar3 support for main build process
2020-11-13 12:13:14 +01:00
Badlop f9b8dfd400 Update dependencies 2020-11-11 15:53:16 +01:00
Paweł Chmielowski 81e872c110 Don't do double utf-8 conversion on translated strings in str:format
This caused garbled text in some places in webadmin when using language
that used characters > 128.

Thanks to chengshq for noticing this and providing preliminary patch.
2020-11-09 12:20:35 +01:00
Badlop 9ed2ca5079 Document sql_odbc_driver option (copied from docs site) 2020-11-06 16:39:02 +01:00
Badlop e7e9ca54df Document outgoing_s2s_ipv4_address and ipv6 options (#3396) 2020-11-06 15:52:33 +01:00
Holger Weiss 23a18b1a60 Apply cosmetic changes to outgoing s2s IP options 2020-11-04 13:12:06 +01:00
Holger Weiss 0a88f9c8a9 Merge remote-tracking branch 'processone/pr/3396'
* processone/pr/3396:
  Add outbound s2s out interface (ipv4/ipv6)
2020-11-04 12:19:49 +01:00
Paweł Chmielowski de51ba331e Make sure that jid used as base in mam xml_compress is bare 2020-11-04 10:56:49 +01:00
Holger Weiss d37b2f851d mod_push: Fix log message argument 2020-11-04 10:10:20 +01:00
Holger Weiss f40c5c304d mod_push: Fix API call return type on error
A call that yields a 'rescode' isn't supposed to return an error tuple.
2020-11-04 09:07:30 +01:00
Holger Weiss 37c75f556d mod_push: Support cache config changes on reload 2020-11-04 09:04:30 +01:00
Paweł Chmielowski ec61c2f3dc Change split character in PROXY_USER from \x04 to :
This is clearly typo
2020-10-29 16:36:18 +01:00
Paweł Chmielowski d02c7d3b3b Update eimp
This makes eimp compile correctly agains headers from png12
2020-10-26 16:12:58 +01:00
Paweł Chmielowski a2dfd2e0b9 Update eimp 2020-10-26 10:53:52 +01:00
Paweł Chmielowski b4ea1625e4 Don't use same value in cache for user don't exist and wrong password
By doing this check_password that returned info about mismatched password
caused user_exists checks performed after that to return wrongly that
account doesn't exist.
2020-10-22 11:10:22 +02:00
Paweł Chmielowski 7655e10ba4 Add better error reporting to mod_muc_admin commands 2020-10-20 17:57:19 +02:00
Badlop b64fff1faa Document that send_direct_invitation is asynchronous 2020-10-16 15:24:58 +02:00
Badlop f1e04639bb Support for MAM Flipped Pages (#3398) 2020-10-15 21:42:43 +02:00
Paweł Chmielowski 73dbd34f95 Store room options in create_room_with_opts only if we will start room
Previously we could overwrite existing room options and then later return
error because room was already started.
2020-10-15 16:24:50 +02:00
Jerome Sautret 6bbae4cea2 send_direct_invitation command is now asynchronous
EJABS-3593
2020-10-15 11:40:22 +02:00
Paweł Chmielowski b95d67aefb Make websocket send put back pressure on c2s process
Previously c2s was free to generate data to send in unlimited manner, and
just generate queue of messages that are waiting to be send. This could lead to
hitting timouts in stream management ack handling (if c2s generate lot of
packages, after which <r> request was sent, client could even not receive it
before timeout was triggered on server waiting for corresponding <a>).

This changes makes c2s process wait for data being sent to tcp socket
associated with websocket connection, which should help with this problem.
2020-10-13 14:57:33 +02:00
Paweł Chmielowski 73f8aded17 Make mod_muc_admin command work correctly with hibernated rooms
This should first try to unhibernate rooms before trying to send messages
to processes handling them.
2020-10-13 13:00:57 +02:00
Jerome Sautret fdda572c9a Added sql_odbc_driver option for mssql db
Add an option to choose the ODBC driver when sql_type is set to mssql
2020-10-08 16:23:34 +02:00
Holger Weiss e4d6007293 ejabberd_stun: Rename Logger filter
Don't overwrite the Logger filter added by the 'stun' application (which
appends metadata to STUN/TURN log messages).

Closes processone/stun#31.
2020-10-01 16:37:36 +02:00
Holger Weiss df58ee924f mod_register: Allow for account-removal-only setup
Since commit de91618070, it was no longer
possible to configure mod_register so that only account removal (i.e.,
no registration) is permitted.  Revert to the previous behavior which
allows admins to freely configure account registration and removal via
separate access rules.
2020-09-29 06:11:30 +02:00
Stu Tomlinson d9c1befbfc Add sql dir to extra_src_dirs
When running ct under rebar3, add sql dir to extra_src_dirs so sql
scripts are available to run clear_sql_tables
2020-09-25 18:45:41 +01:00
Stu Tomlinson b173ca2fd0 Fix docker DB initialization
The docker local copies of DB initialization scripts were out of sync
with the master copies. Instead of updating local copies, adjust docker
compose to reference master copies directly.

Also change docker config to use docker volumes instead of mounted
directories for all DB data.
2020-09-25 18:13:35 +01:00
Stu Tomlinson 27ed8f5647 Improve rebar3 configure-deps plugin output
Switch to using rebar_utils:sh/2 instead of os:cmd/1 to spawn ./configure
so that output can be monitored and errors detected
2020-09-23 17:56:49 +01:00
Stu Tomlinson 714bc2d329 Miscellaneous rebar3 fixes
Correct Makefile clean targets

Fix a few more include() -> include_lib() for depedency includes

Use project_app_dirs to reference elixir app from rebar3 (lib_dirs is
no longer supported)
2020-09-23 15:52:21 +01:00
Badlop d9cb6d1af7 log_rotate_date and log_rate_limit are deprecated since e4a8afb (#3382) 2020-09-22 13:58:56 +02:00
Paweł Chmielowski 583dd15beb Make roster subscriptions work better with invalid roster state in db
Sometimes we can observer combinations of subscription/ask that shouldn't
happen normally, but can be generated with api calls, let's try to handle
that gracefully instead of crashing.
2020-09-22 13:48:49 +02:00
Daniel Kenzelmann 604cc9bb3a Add outbound s2s out interface (ipv4/ipv6)
Adding options taking IPs as string:
outgoing_s2s_ipv4_address: "1.2.3.4"
outgoing_s2s_ipv6_address: "2000:1:1:1::1"
2020-09-21 22:18:46 +02:00
Stu Tomlinson 0fc1aea379 rebar3 support for main build process
This adds support for building, and installing, ejabberd using rebar3

A --with-rebar=/path/to/rebar3 option is added to configure to specify
which rebar to use

rebar2 compatibility is maintained, and the bundled rebar2 is still
used by default
2020-09-21 15:14:12 +01:00
Stu Tomlinson 385af01587 rebar3 plugin to support configure-deps command (#3392)
* rebar3 plugin to support configure-deps command

To allow running configure on dependencies prior to compilation, add a
rebar3 plugin to support the 'configure-deps' command introduced for
rebar2 in a7639fd4

* Fix compatibility with OTP < 23

binary_to_atom/1 is new to OTP 23
2020-09-21 13:51:31 +02:00
Stu Tomlinson d9feed54a9 Add 'gitonly_deps' list to rebar config/script (#3391)
Add list of dependencies that should only be built from git, to support
building with rebar3 where deps do not have hex packages (or where the
package versions do not directly map to git tags).

This is required for elixir and luerl deps.
2020-09-21 13:49:58 +02:00
Paweł Chmielowski b89f3c442c Use os time instead of system time in values returned by mod_time
This timer should correctly work with time warps, and should fix
issue #3390
2020-09-15 12:11:15 +02:00
Badlop 9629601d0b Refer to the XEP for standard names (processone/docs.ejabberd.im#97) 2020-09-11 12:27:05 +02:00
Holger Weiß e9a053f7ac Allow for filtering outgoing s2s stanzas (#3381)
Let 's2s_send_packet' hook callbacks filter stanzas, analogous to the
's2s_receive_packet' hook.
2020-09-07 10:12:19 +02:00
Badlop a75966f1a2 Revert "Run user_receive_packet in send_message so MAM stores also incoming (#3377)"
This reverts commit 43f813d6f8.
2020-09-04 11:37:18 +02:00
Badlop 43f813d6f8 Run user_receive_packet in send_message so MAM stores also incoming (#3377) 2020-09-03 17:47:11 +02:00
Stu Tomlinson eada3b6e93 Fix syntax for lager dependency version (#3379)
Add 'tag' to lager dependency so that build with rebar3 will pull from
hex package instead of git checkout matching other dependencies
2020-09-03 15:35:34 +02:00
Paweł Chmielowski 90e0293df3 Update one more place where we had -include("xmpp.hrl") 2020-09-03 14:30:04 +02:00
Stu Tomlinson bd11a00f8f Use include_lib() to include headers from dependencies (#3369) 2020-09-03 13:45:57 +02:00
Paweł Chmielowski 54af08799d Update xmpp dep 2020-09-03 13:43:49 +02:00
Stu Tomlinson b71708aab9 Update base64url dep for rebar3 (#3368)
Update base64url version to match available hex package to support
compilation with rebar3
2020-09-03 13:40:04 +02:00
Badlop a3be28b5c4 Provide room disco info identity name only when title was set (#3370) 2020-08-28 14:56:25 +02:00
Badlop 743b25448a New hook to run when a room process is started (#3353) 2020-08-28 14:54:06 +02:00
Badlop 66c2f45bff Show nick also in oneself list of subscriptions (#3206) 2020-08-26 19:32:29 +02:00
Badlop 8d969a4a9f Always show MucSub subscribers nicks (#3206)(thanks to Snoopcatt) 2020-08-26 19:32:26 +02:00
Badlop bf62cf3db6 Add link to docs about default and new database schemas 2020-08-26 11:46:23 +02:00
Holger Weiss 8daea451e3 mod_pubsub: Fix typo in 'hosts' documentation
Thanks to Melvin Keskin for spotting this.
2020-08-25 08:21:43 +02:00
Badlop 864188ad65 Mark dangerous buttons with CSS (#3363) 2020-08-24 16:44:07 +02:00
Holger Weiss 65260e2449 ejabberdctl: Avoid bashisms
Don't let the ejabberdctl script depend on non-POSIX syntax.  (Also, fix
a typo and avoid tabs.)
2020-08-24 06:42:45 +02:00
Badlop b9926c6796 Update opt files with "make options" 2020-08-21 18:09:03 +02:00
Badlop e7575ab63f For mod_vcard_* modules, redirect options to mod_vcard 2020-08-21 18:08:59 +02:00
Badlop 92913389a5 Fix vCard search by User when using Mnesia
Reported in
https://stackoverflow.com/questions/63499864/how-to-search-registered-user-on-ejabberd-server-from-client-side-using-smack-li
2020-08-20 16:46:06 +02:00
Holger Weiss 65be619907 mod_pubsub: Remove 'dag' node plugin documentation
Commit c9d3beb9eb removed the 'dag'
node/nodetree plugins.
2020-08-18 06:50:33 +02:00
Paweł Chmielowski ee76581b49 Add rebar.config* files when publishing to hex from mix
This should help with issue #3354
2020-08-11 10:09:23 +02:00
Badlop 842ec1494c Fix to allow vhost admins to view WebAdmin menus (#3355) 2020-08-10 21:17:59 +02:00
Badlop 8aa0f7073f Copy Erlang compilation definitions from rebar.config to Docker (#3350) 2020-08-10 12:29:40 +02:00
Paweł Chmielowski 8a645a2d3d Don't forget not-persistent rooms in load_permanent_rooms
Only non-persistent rooms that we are storing are those that were hibernated
but also have mucsub subscribers in them. I don't think it makes sense to
destroy those rooms on restart/reload if we didn't destroy them in first
place when last member did leave room, let just handle those rooms like
they are persistent, and kill them only when all user unsubscribe from them
or they are destroyed from api.
2020-08-06 11:44:44 +02:00
Badlop 4a54395561 Improve explanations of cafile options 2020-08-03 15:18:50 +02:00
Mickael Remond b109c5927e Update mix.exs ejabberd version 2020-07-30 18:32:31 +02:00
Paweł Chmielowski 23beaa9fad Update mix dependencies 2020-07-30 17:57:52 +02:00
Jerome Sautret 839229b5f0 Check if TERM is set before running a remote debug shell 2020-07-30 10:33:38 +02:00
Jérôme Sautret b89b0f140a Merge pull request #3346 from processone/ejabberd-3343
Allow passing Erlang VM args through vm.args config file
2020-07-30 10:31:12 +02:00
Mickael Remond 09454e1658 Allow passing Erlang VM args through vm.args config file
This can be used to define the Erlang cookie in a place that feels less foreign to
non Erlang users.

Fixes #3343
2020-07-29 17:35:59 +02:00
Paweł Chmielowski 828c0ad1e0 Update deps 2020-07-28 14:38:34 +02:00
Paweł Chmielowski 87bbd9cb02 Update stun 2020-07-28 14:04:00 +02:00
Paweł Chmielowski 70507a694c Update changelog 2020-07-28 13:25:27 +02:00
Paweł Chmielowski 1b168e7d5c Add support for unix socket in listeners
To use it you just need to set port value to "unix:/path/to/socket"
2020-07-28 12:19:30 +02:00
Paweł Chmielowski d5935fd1ad Don't log http errors when socket get closed after processing one request 2020-07-28 12:19:30 +02:00
Badlop 2bcd2c38a9 No need to check for Erlang 17, as 19 is the lowest supported anyway
This rollsback the conditional introduced years ago in c2753cd51c
2020-07-28 11:28:04 +02:00
Badlop 042cddb768 Elixir was required for quicktest, that was removed in 2018 51cbbf313 2020-07-28 11:26:41 +02:00
Badlop e0b7fd72af Update Stun to 1.0.36, and Esip too 2020-07-28 11:25:43 +02:00
Badlop 9c5e4454e4 Sort dependencies and improve some indentation 2020-07-22 18:03:28 +02:00
Badlop 7fe0b8d274 Revert "Modify ERL_LDFLAGS of deps when compiling on R23 on rebar2"
This reverts commit 21312c79aa.
2020-07-22 10:08:14 +02:00
Badlop 90ca689123 Update dependencies, they now compile with Erlang/OTP 23.0 natively 2020-07-22 10:06:06 +02:00
Badlop db2825342c Revert "Dirty workarounds to compile jiffy with Erlang/OTP 23 (#3282)"
This reverts commit 2ca5712507.
2020-07-15 12:12:42 +02:00
Badlop bc1de531cc Update jiffy to 1.0.5 which supports Erlang/OTP 23 2020-07-15 12:12:39 +02:00
Badlop 2ea5f7856c In fact misc:try_url/1 is not used anymore 2020-07-15 11:41:51 +02:00
Badlop e5b66aadaf Fix try_url/1 parsing of uri_parse result format, reported by Dialyzer 2020-07-14 12:21:37 +02:00
Holger Weiss cff7c4c100 Update 'stun' dependency to tagged version 2020-07-11 17:53:33 +02:00
Holger Weiss e30592c050 mod_stun_disco: Fix function specification 2020-07-11 17:51:20 +02:00
Badlop ff92dab49e Parse also ServerHost in create_room* commands (#3326) 2020-07-10 13:06:05 +02:00
Badlop f652f8c8d6 Fix crash when creating new MUC log file in non-ASCII lang (#3324) 2020-07-10 12:03:12 +02:00
Badlop 80a502782b Use the same leading sentence than other sections 2020-07-06 16:39:15 +02:00
Holger Weiss 3bf7fbc117 ejabberd_stun: Filter info/debug messages
Update 'stun' dependency, and drop the info/debug messages now logged by
the 'stun' application if OTP's new logging API is used.
2020-07-01 21:53:22 +02:00
Badlop 0ff5b44d15 Fix YAML syntax in example configuration (#3301) 2020-06-25 12:39:44 +02:00
Badlop 61926a44be Subscriber should not send message to moderated room (#3222) 2020-06-24 13:17:04 +02:00
Holger Weiss ec5f369d9d ejabberd_logger: Avoid excessive stat calls
By default, the logger_std_h module shipped with OTP 21.0 and newer
reads the log file information prior to each and every write operation.
This is done to play well with external log rotation tools.

In order to minimize the performance penalty in situations where the log
file is flooded, configure logger_std_h to skip reading the file
information as long as no more than one second has passed since it was
last read.
2020-06-23 21:27:12 +02:00
Holger Weiss dbebcd08c7 README.md: Add line breaks after feature titles 2020-06-23 00:31:22 +02:00
Paweł Chmielowski 768460b518 Correctly handle user_regexp acl rules with not matching host
This should fix issue reported in issue 3304
2020-06-22 10:24:10 +02:00
Holger Weiss 515dfc002b mod_stun_disco: Fix wording of log message 2020-06-19 18:04:26 +02:00
Badlop 16645a3c0a Document that only ejabberdctl can join and leave a local node (#3049) 2020-06-09 13:23:17 +02:00
Badlop 38949bdeea Update example config to include mod_http_upload custom headers (#3288) 2020-06-09 13:08:05 +02:00
Badlop 5f3457dbd6 Add default values so Travis config validation stops warning 2020-06-08 15:27:37 +02:00
Badlop b9108c4650 Travis renamed redis-server to redis apparently 2020-06-08 15:27:28 +02:00
Badlop a54c667c80 Remove old Regexp, the new Re is available since Erlang/OTP R12B-4 2020-06-08 15:27:27 +02:00
Badlop bcd2cd7e93 Remove comment about Erlang/OTP older than R14, as we require 19.3 nowadays 2020-06-08 15:27:25 +02:00
Badlop 337ba42953 Get back some commented specs that required Erlang R12 2020-06-08 15:27:23 +02:00
Badlop 4f5c00a83d Option route_subdomains was deprecated and useless a year ago in ffe1c722 2020-06-08 15:27:18 +02:00
Holger Weiss c6bbdafe92 Update 'yconf' dependency to fix Erlang/OTP 19.x 2020-06-05 20:24:17 +02:00
Badlop f2e81ed2a0 When updating group in cache, first delete so insert succeeds (#3296) 2020-06-05 19:34:00 +02:00
Badlop 7efc208b9e Handle ets_cache return value in shared roster get_group_opts (#3296) 2020-06-05 19:33:52 +02:00
Holger Weiss 266691f929 Update 'yconf' dependency
Fixes #3295.
2020-06-05 17:02:06 +02:00
Paweł Chmielowski 482917348b Update deps 2020-06-03 13:43:10 +02:00
Holger Weiss 945a5cd09c misc: Don't crash on URLs without port number
Let misc:uri_parse/1 return default HTTP(S) port number if the URL
doesn't specify a port number, analogous to the behavior when
USE_OLD_HTTP_URI is defined.
2020-06-03 12:22:14 +02:00
Holger Weiss 9ea51d3295 misc: Make sure uri_parse/1 returns strings
The uri_string:parse/1 function returns the URI elements as strings or
as binaries depending on the input.  Make sure misc:uri_parse/1 returns
strings in both cases, analogous to the behavior when USE_OLD_HTTP_URI
is defined.
2020-06-03 12:02:29 +02:00
Holger Weiss 77308e6aff Merge remote-tracking branch 'processone/pr/3294'
* processone/pr/3294:
  Update example config
2020-06-03 09:41:24 +02:00
Licaon_Kter b0c6caa60e Update example config 2020-06-03 07:19:02 +00:00
Holger Weiss 3cfc5c9633 Update 'turn_ip' option name in test configuration
Thanks to Badlop for spotting this.
2020-06-03 06:13:43 +02:00
Holger Weiss cd336369a5 mod_stream_mgmt: Don't kill new PID on resumption
During XEP-0198 resumption, the ejabberd_c2s process that handles the
new connection reopens the ejabberd_sm session of the old one.  Since
commit b4770815c0, the new process adds
the new session table entry before the old process removes the old one.
While adding the new one, ejabberd_sm checks for old sessions to
replace.  This check assumes old SIDs compare lower than new ones.  This
assumption didn't necessarily hold for the session resumption case,
where the old SID's timestamp was copied over to the new SID and only
the PID was updated.  Therefore, the new process was killed if the new
PID happened to be smaller than the old one.

Fix this by having mod_stream_mgmt use its own SM-ID rather than copying
over the old SID's timestamp to the new SID.

Thanks to Thilo Molitor and Friedrich Altheide for reporting the issue,
and to Thomas Leister for his help with debugging it.
2020-06-01 21:33:55 +02:00
Badlop c62956ab7b Test 23.0 version 2020-06-01 10:35:41 +02:00
Badlop 1d7e29765e Update eimp, sqlite3 and epam to support Erlang/OTP 23 (#3282) 2020-06-01 10:35:37 +02:00
Badlop c0f7008e96 Use old http_uri, crypto and pg2 only with old Erlang/OTP (#3284) 2020-06-01 10:35:28 +02:00
Badlop 2ca5712507 Dirty workarounds to compile jiffy with Erlang/OTP 23 (#3282)
Works for me with:
./configure --disable-pam
./rebar get-deps
./rebar configure-deps
./rebar compile
make install

changes in erlang-native-compiler used by jiffy:

src/rebar_port_compiler.erl
-     {"ERL_LDFLAGS"  , " -L$ERL_EI_LIBDIR -lerl_interface -lei"},
+     {"ERL_LDFLAGS"  , " -L$ERL_EI_LIBDIR -lei"},

src/rebar_utils.erl
--dialyzer({no_missing_calls, escript_foldl/3}).
2020-06-01 10:33:06 +02:00
Holger Weiss 7a37483307 Rename 'turn_v4_ip' and 'turn_v6_ip' options
The 'turn_ipv4_address' and 'turn_ipv6_address' option names are
probably more intuitive.
2020-05-29 18:40:19 +02:00
Paweł Chmielowski 21312c79aa Modify ERL_LDFLAGS of deps when compiling on R23 on rebar2
Newer version removed erl_interface, and default rebar2 ERL_LDFLAGS will
try to link it, this change should pass correct flags to compiler.
2020-05-26 11:01:22 +02:00
Holger Weiss 56d00e427d ejabberd_stun: Add 'turn_blacklist' option
The new 'turn_blacklist' listener option allows for specifying one or
more IP addresses and/or subnet addresses/masks.  The TURN server will
refuse to relay traffic from/to blacklisted IP addresses.  By default,
Teredo and 6to4 addresses are blacklisted, as mandated by RFC 6156
(section 9.1).
2020-05-21 21:46:02 +02:00
Holger Weiss 7bb4da2fee mod_stun_disco: Make 'services' example shorter
Omit the 'tcp' and 'stuns' services from the list of example 'services'
in the documentation.  For typical use cases, those are less interesting
than 'udp' and 'turns' services.
2020-05-19 23:23:24 +02:00
Holger Weiss f19b975e8d mod_stun_disco: Offer local IPv6 services
Also announce local STUN/TURN services listening on IPv6 sockets (unless
the 'offer_local_services' option is set to 'false').
2020-05-19 22:55:12 +02:00
Holger Weiss 83fa637569 ejabberd_stun: Support IPv6 for TURN
The stun application now supports RFC 6156: TURN Extension for IPv6, and
therefore needs separate IPv4 and IPv6 relay addresses.
2020-05-19 21:42:41 +02:00
Holger Weiss 858bfb4b80 Let ejabberd_stun listen on IPv6 sockets
The stun application now allows IPv6 clients to perform STUN requests
and to allocate TURN relays.
2020-05-19 20:22:58 +02:00
Badlop 42c82c9e72 Fix hardcoded URL to register.css and URLS to sections (#3281) 2020-05-19 19:32:06 +02:00
Badlop 8efdd439f1 Update man page to ejabberd 20.04 2020-05-19 16:38:11 +02:00
Badlop 70977cbb13 Sort databases alphabetically in options doc (thanks to Neustradamus)(#3246) 2020-05-19 16:38:08 +02:00
Badlop ad31fbee1e Sort alphabetically configure options (thanks to Neustradamus)(#3246) 2020-05-19 16:38:05 +02:00
Paweł Chmielowski 6f54b6ae3b Don't crash in mod_muc_log:get_url when mod_muc_log is not enabled
Disco on room can call this function even when logger is not enabled,
but this room option was enabled previously when logger was active.
2020-05-15 13:44:09 +02:00
Badlop e94b89a57d Display installed ejabberd version in webadmin footer (#3272) 2020-05-15 11:20:53 +02:00
yuriyz-w 44528d3fef Make SQL query more generic for MSSQL compatibility (#3271) 2020-05-15 09:19:55 +02:00
Paweł Chmielowski 4580feaa3c Increase default shaper limits, to help with jingle initiation delay
More discussion about this can be found in pull request 3255
2020-05-15 09:10:57 +02:00
Badlop f3b8dc9c0b Update *_vcard commands help, so they are better displayed in Docs 2020-05-14 20:02:47 +02:00
Badlop 9d923e8e6d Update syntax of some options so they are better displayed in Docs 2020-05-12 21:33:00 +02:00
Badlop c861fa6a6a Revert service_subscription_subscribers test that is iconsistent (#2696) 2020-05-11 22:25:56 +02:00
Badlop d7d8085d3b Fix most EDoc errors, even if that's not used nowadays apparently 2020-05-11 19:53:13 +02:00
Badlop 5e70a47f20 If new session Pid exists when sm_remove is called, then keep Ping (#3260) 2020-05-11 18:22:35 +02:00
Holger Weiss e286bb23db mod_stun_disco: Bump credentials_lifetime default
Increase the default lifetime of temporary credentials to 12 hours.
ejabberd's built-in TURN server re-queries the temporary password from
mod_stun_disco whenever a TURN client attempts to refresh an allocation,
and mod_stun_disco will only return the password as long as the
credentials didn't expire.  Therefore, the credentials lifetime
effectively limits the maximum lifetime of a TURN allocation when
ejabberd's TURN service is used, so the default value shouldn't be too
short.
2020-05-11 17:32:28 +02:00
Badlop 2c42bd07c8 Fix link in mod_sip to SIP Docs section 2020-05-09 16:10:26 +02:00
Badlop 2001540143 Provide minimal mod_bosh configuration example 2020-05-09 15:04:10 +02:00
Badlop d88a32992a Add link in acme option to ACME section in ejabberd Docs 2020-05-09 11:45:39 +02:00
Badlop 64c09c20eb Hide false-positive warnings about mod_delegation Type atom and NS binary 2020-05-07 22:29:54 +02:00
Badlop c990704418 Remove ancient and rather useless incode ejabberd_commands documentation 2020-05-07 19:38:12 +02:00
Badlop edf5b3c7f0 Don't use string:take, as it isn't available in Erlang/OTP 19.3 (#3256) 2020-05-07 16:09:51 +02:00
Badlop e5a2d42484 Fix webadmin muc room sorting broken due to trailing slash patch (#3256) 2020-05-07 11:22:43 +02:00
Paweł Chmielowski 51e45516a4 Unconditionally send presence unavailable to all pres_a recipient
Previously we only send that presence to direct presence recipients if
client also sent general self presence (without to attribute).

This should help with issue #3245
2020-05-07 10:40:18 +02:00
Badlop 41b06cb79e Show deprecation warning if ejabberd_xmlrpc is configured as listen module (#2915) 2020-05-06 14:08:43 +02:00
Badlop d8509aec12 Remove access_commands useless lines, api_permission replaced it years ago 2020-05-06 14:08:40 +02:00
Holger Weiss 5649e35a64 ejabberd_listener: Let supervisor terminate child
If a TCP connection was closed before the socket was handed over to a
supervised child process, let the supervisor terminate the process
rather than killing it directly.  This avoids crash log entries
generated by the supervisor.
2020-05-05 17:22:52 +02:00
Holger Weiss 865074603c Set 'max_fsm_queue' default value (back) to 10000
The default value for the 'max_fsm_queue' option was set to 10000 in
commit 79685da90b, and that value is still
documented to be the default.  It was (probably unintentionally) changed
to 5000 in commit 03de853e4f.

It makes sense to keep it larger than the value of mod_stream_mgmt's
'max_ack_queue' option.
2020-05-05 01:34:12 +02:00
Holger Weiss 6d13120e69 mod_stun_disco: Log discovered services on startup
If the 'offer_local_services' option isn't set to 'false', log an [info]
message for each auto-discovered ejabberd_stun listener on startup (and
on configuration reload).
2020-05-05 01:02:50 +02:00
Badlop e6a3b1fa68 Extract translatable strings also from the xmpp library 2020-05-04 16:25:42 +02:00
Badlop df66fa6a48 Fix the new service_subscription_subscribers test (#2696) 2020-05-04 11:31:52 +02:00
Marc Tonnes 5d499c7173 Fix @from attribute on MucSub 'subscribers' node messages 2020-05-04 11:31:24 +02:00
Holger Weiss b1e967eaf3 mod_stun_disco: Remove unnecessary inclusion 2020-05-03 17:27:41 +02:00
Holger Weiss 151fa2ec50 mod_stun_disco: Apply minor documentation cleanups 2020-05-03 17:20:15 +02:00
Holger Weiss e4de03f3df mod_stun_disco: Try to resolve listener address
In some IPv6-only networks, hostnames that have no AAAA record are
resolved to an IPv6 address that's mapped to the host's IPv4 address.
This allows the IPv6-only clients to communicate with IPv4-only services
such as ejabberd's built-in STUN/TURN server.  If STUN/TURN clients try
to contact the IPv4 address directly rather than using the mapped IPv6
address, the connection will fail.

Therefore, try to resolve the IP address of local ejabberd_stun services
to the hostname and announce that hostname rather than the IP address if
(and only if) the hostname resolves back to the original IP address, and
not to any additional IPv4 or IPv6 address(es).

This can (and should) be reverted once IPv6 support is added to
ejabberd's built-in STUN/TURN server.
2020-04-30 22:40:01 +02:00
Jerome Sautret 724d09a510 Set ejabberd version to 20.04 2020-04-29 16:29:59 +02:00
Badlop fba6a64648 Fix English typos in configure.ac 2020-04-29 12:07:35 +02:00
Jérôme Sautret 0539637d30 Merge pull request #3232 from weiss/enable-stun
Enable STUN/TURN support by default
2020-04-29 10:29:05 +02:00
Badlop 4a7d42647f Rewrite sentences in modules options examples, to not break Docs indentation 2020-04-28 21:31:35 +02:00
Paweł Chmielowski b56663ef07 Update dependences in mix 2020-04-28 17:23:36 +02:00
Paweł Chmielowski 25597a4326 Run tests for mssql only if configured with --enable-mssql 2020-04-28 16:52:08 +02:00
Paweł Chmielowski 56c8f6b280 Update deps 2020-04-28 16:24:40 +02:00
ChaosKid42 abc3260e75 enable tests with mssql-backend (#3136) 2020-04-28 16:22:42 +02:00
Jérôme Sautret 24a11fc8e8 Merge pull request #3235 from weiss/xep-0215
Support STUN/TURN service discovery
2020-04-28 16:03:21 +02:00
Holger Weiss 6eb2f07274 ejabberd_stun: Tone down 'auth_realm' warning
These days, STUN/TURN authentication can be performed with ephemeral
credentials, where the REALM is irrelevant. Therefore, just log an
[info] message rather than a [warning] in the case where no
authentication REALM is configured but multiple virtual domains exist.
2020-04-28 10:34:43 +02:00
Holger Weiss 9cd47d7085 Add tests for mod_stun_disco 2020-04-28 10:34:43 +02:00
Holger Weiss 69d1d62add Support XEP-0215: External Service Discovery
Add the 'mod_stun_disco' module, which allows XMPP clients to discover
STUN/TURN services and to obtain temporary credentials for using them as
per XEP-0215: External Service Discovery.  The temporary credentials
handed out to clients have the format described in:

https://tools.ietf.org/html/draft-uberti-behave-turn-rest-00

Also add the new module to the example configuration file.

Closes #2947.
2020-04-28 10:34:43 +02:00
Badlop 3db9459591 Don't offer X-OAUTH2 if the only auth method enabled is Anonymous (#3209) 2020-04-27 20:03:21 +02:00
Paweł Chmielowski 6320dfd34e Don't store caps information for direct presences of muc room
We really don't need those, and thanks to each individual room having
different hash (as one of hashed data is room description) we end with
lot of data that we really don't need.
2020-04-27 13:17:51 +02:00
Badlop 055fe744d3 Clean some unused functions in ejabberd_ctl, this makes "make hooks" happy 2020-04-24 20:36:24 +02:00
Christoph Scholz d7c696f97c mix.exs: Update 'xmpp' and 'stun' 2020-04-23 20:05:40 +02:00
Holger Weiss fc444ce503 rebar.config: Update 'xmpp' and 'stun'
Use the current versions of 'xmpp' (to get XEP-0215 support) and 'stun'
(to fix TURN issues).
2020-04-23 20:05:40 +02:00
Holger Weiss 88f392721b gen_mod: Reload modules after reloading listeners
Make sure modules won't be reloaded before listeners.  This is necessary
to allow the (not yet committed) 'mod_stun_disco' module to parse the
listener configuration after configuration reloads.
2020-04-23 20:05:40 +02:00
Holger Weiss c55e7b8499 ejabberd_stun: Fix 'turn_ip' fallback
The 'turn_ip' option validator doesn't accept an inet:ip4_address()
tuple.

While at it, change the logic to only perform the fallback address
lookup if no 'turn_ip' is configured (analogous to the fallback
mechanism for the case where the 'auth_realm' is undefined).
2020-04-23 18:32:40 +02:00
ChaosKid42 1f7ca91670 use dsn-less config for mssql (#3131) 2020-04-23 13:56:41 +02:00
Licaon_Kter d9131c854d Bump jiffy so it compiles on older GCC (#3218)
* Update jiffy

* And here
2020-04-23 13:29:33 +02:00
Holger Weiss 09a87f5a0c ejabberd_stun: Handle hashed passwords gracefully
Don't crash when STUN/TURN authentication is performed against a
SCRAM-hashed password.
2020-04-22 00:16:03 +02:00
Holger Weiss 1db70edcf8 ejabberd_stun: Add 'stun_get_password' hook
Add a hook that allows modules to offer a password for STUN/TURN
authentication.
2020-04-22 00:09:42 +02:00
Badlop 1a3533e4a2 Fix some English typos 2020-04-21 20:58:01 +02:00
Badlop 3db9de26e9 Rephrase mod_admin_extra doc, a2x screwed the format when building Docs 2020-04-21 20:11:39 +02:00
Badlop 78f0439e78 Make a few more strings translatable in MUC and Shared Roster WebAdmin 2020-04-20 20:24:56 +02:00
Badlop b124e911d3 Update some translated strings where only print chars had changed 2020-04-20 20:24:50 +02:00
Holger Weiss c836dc66a8 ejabberd_stun: Set a default 'turn_ip'
Try to resolve the local hostname, use the result as the default
'turn_ip', and only log a warning if that fails.  Using the local
hostname's address by default is analogous to mod_proxy65's behavior.
2020-04-20 08:42:32 +02:00
Holger Weiss b1b3c4cdcf Enable STUN/TURN by default
Build ejabberd with STUN/TURN support by default, and add a STUN/TURN
listener to the example configuration file.
2020-04-20 00:37:41 +02:00
Holger Weiss b0f95975c2 Travis CI: Test against Erlang/OTP 22.3 2020-04-19 15:39:34 +02:00
Badlop 2e48c24638 Updated Spanish translation 2020-04-17 19:29:17 +02:00
Badlop 7359eb6246 Updated Catalan translation 2020-04-17 19:23:21 +02:00
Badlop 99d21bca49 Don't extract for translation strings from man pages, at least for now 2020-04-17 19:23:18 +02:00
Badlop 1b98084918 Fix previous commit 2020-04-17 19:23:13 +02:00
Badlop d311eaf8f3 Log messages generated by msgmerge and display unexpected ones 2020-04-17 17:28:43 +02:00
Badlop 0355e15a42 Fix doc content in mod_admin_extra so it can be extracted by make translations 2020-04-17 17:28:39 +02:00
Badlop 101f7a6d63 Check if mod_muc_log is enabled before setting logging option (#3215) 2020-04-17 16:19:58 +02:00
Badlop 4aa85c538c When rescode is some unexpected, probably error message, print it 2020-04-17 16:19:55 +02:00
Paweł Chmielowski 22980ed8a5 Restart offline pop_messages when there is mismatch between select and delete
When another connection is inserting something to spool at this same time
as we do pop_messages, it's possible that insert will happen between we
fetch messages and delete them, so we effectively will delete it without
delivering it to client. This change catch this situation and restart
transaction, so we should always have consistent results.
2020-04-17 15:30:28 +02:00
Paweł Chmielowski cb1c0a3188 Update mysql driver to get rid of warning 2020-04-16 18:26:13 +02:00
Badlop 0705695e02 Update documentation of mod_shared_roster (#3214) 2020-04-16 13:12:32 +02:00
Paweł Chmielowski c11922e2a2 Make session iq response have from be set to server jid
It looks like old version of Smack don't accept request that are have
from sent to sender jid, but are only working when jid is set to server
address. This is also how it looks in old xmpp rfc examples.
2020-04-16 13:05:42 +02:00
Paweł Chmielowski 37226dd41f Resending unacked stanzas should send even archived msgs if mod_offline is enabled
Messages that are received when no c2s is active will be stored in offline,
even when mam archived them, so i don't think we should be doing something
different in this case.
2020-04-16 13:04:12 +02:00
Badlop cd0b65f4d5 Fix unused variables from previous commit 2020-04-14 15:00:45 +02:00
Badlop b7c088d4b0 Update links to the ejabberd Docs page in WebAdmin 2020-04-14 13:59:11 +02:00
Badlop e197b25e82 Rename opts->name to label, to avoid confusion with the group name (#3214)
Also updated WebAdmin to show more meaningful explanations
Also fixed a bug that break support for group@host in Displayed
2020-04-14 13:58:53 +02:00
Jérôme Sautret b02506eaaf Merge pull request #3132 from area-42/publisher_mssql_text_to_varchar
change PubSub publisher from text to varchar for mssql
2020-04-10 16:20:43 +02:00
Badlop 8694517c34 Minor fixes in doc 2020-04-09 16:30:21 +02:00
Badlop 2febd1c220 Copy more option explanations from ejabberd Docs site 2020-04-08 18:49:41 +02:00
Badlop aa0ed37034 Add ejabberd version number to man pages 2020-04-08 18:48:09 +02:00
Badlop da18245d9a Indicate which ejabberd version is used to produce the page 2020-04-08 18:47:50 +02:00
Badlop 5cc9a1fe44 Don't make commands subsections, so Docs TOC plage is cleaner 2020-04-08 18:45:29 +02:00
Badlop de0aead1cd Fix set_loglevel example argument documentation 2020-04-08 18:44:09 +02:00
Badlop 624ba7e94f Improve formatting of mod_announce doc 2020-04-08 18:42:45 +02:00
Paweł Chmielowski 9bb3aee0e2 Make resumed sessions try to deliver possibly queued messages to new session
Between receiving resume request and being closed by new session, it's
possible (even if not very likely) that new messages would arrive to
process that is resumed. In that case try to reroute messages that were
received after we sent resume reply to new process.
2020-04-07 14:51:49 +02:00
Paweł Chmielowski 16585713f8 Log errors that happen when retrieving http headers in ejabberd_http
It seems that ssl errors can be generated here, so lets have abily to show
them instead of swallowing them silently.
2020-04-07 13:50:01 +02:00
Holger Weiss e01e528235 mod_carboncopy: Bump supported XEP revision
Since mod_carboncopy supports "urn:xmpp:carbons:rules:0", it implements
version 0.13.x of XEP-0280.
2020-04-05 22:52:55 +02:00
Paweł Chmielowski eac7e3488c Remove bash-izm from ejabberdctl.template introduced recently 2020-04-03 17:28:27 +02:00
Jerome Sautret 762486d199 Limit number of atoms used by ejabberdctl ( #2977) 2020-04-02 15:51:16 +02:00
Badlop 23493ce239 Document mod_shared_roster_ldap options 2020-04-02 12:56:43 +02:00
Badlop 510ab53341 Add ejabberd_auth_http auth_opts brief description 2020-04-02 12:56:40 +02:00
Badlop 220cf73318 Document sql_prepared_statements 2020-04-02 12:56:38 +02:00
Badlop f6d102f5e2 Quick document with forward link api_permissions 2020-04-02 12:56:36 +02:00
Badlop 05b68764cc Document some global options 2020-04-02 12:56:33 +02:00
Badlop 4e51e82ccf Add three missing mod_bosh options 2020-04-02 12:56:31 +02:00
Badlop 116fa8e9ca add missing mod_mam options 2020-04-02 12:56:28 +02:00
Badlop ce6fd654a0 Fix mod_pubsub indentation 2020-04-02 12:56:26 +02:00
Badlop 5ee2f48aea Add mod_pubsub configuration documentation 2020-04-02 12:56:23 +02:00
Paweł Chmielowski ccb47a67c4 Don't replace %25 in webadmin test on older erlangs
It seems that is a bug in R21+ httpc, so let's try to keep that test
working with older versions
2020-04-01 17:11:19 +02:00
Paweł Chmielowski a2e6d8bb6b Make stop_ejabberd test also work without receiving </stream:stream> 2020-04-01 15:34:06 +02:00
Paweł Chmielowski 1bd560f3f2 Fix potential message loss in terminating c2s sessions
Calling sync version of xmpp_stream_in/out:stop could lead to messages
never being processed by c2s process if they were queued in p1_server.

This could be reproduced by when having messages in offline storage,
starting sessions, enabling stream_mgmt, sending initial presence, and then immediately
</stream:stream>, messages that mod_offline would send process would not
be bounced back by stream_mgmt.
2020-04-01 14:36:01 +02:00
Badlop 222bb1d55d Use different username than other tests, but still include the test chars 2020-04-01 12:50:52 +02:00
Paweł Chmielowski a5ea3fa282 Better error reporting in pubsub tests 2020-04-01 11:45:01 +02:00
Paweł Chmielowski 6c52438128 Make webadmin tests use different user for changepassword/unregister
Using username that is shared with other tests causes login problems in
other places.
2020-04-01 11:44:38 +02:00
Badlop 0508dce2ed Add more webadmin tests 2020-03-31 19:28:36 +02:00
Boris Chernov 87dda1b638 sql_type should be taken for LServer, not LHost (#3202)
sql_type option should be retrieved for the main domain, not the MUC subdomain
2020-03-30 09:47:36 +02:00
Paweł Chmielowski 5ec214386e Make webadmin redirect to page that end with / 2020-03-26 14:17:48 +01:00
Paweł Chmielowski 73ba38ae35 Revert "Pass base path instead of level to support URL missing slash (#3177)"
This reverts commit e9d1201ea8.
2020-03-26 13:43:24 +01:00
Paweł Chmielowski 1ffa9a0cf5 Do not change to attribute of sent messages from bare to full jid
This is not correct per xmpp spec
2020-03-25 16:00:16 +01:00
Christoph Scholz 248cc2d013 change publisher from text to varchar for mssql 2019-12-28 15:49:37 +01:00
227 changed files with 6545 additions and 4118 deletions
+7 -2
View File
@@ -2,10 +2,15 @@ language: erlang
otp_release:
- 19.3
- 22.2
- 22.3
- 23.0
os: linux
dist: xenial
services:
- redis-server
- redis
- postgresql
before_install:
+62
View File
@@ -1,3 +1,65 @@
# Version 20.12
- Add support for `SCRAM-SHA-{256,512}-{PLUS}` authentication
- Don't use same value in cache for user don't exist and wrong password
- outgoing_s2s_ipv*_address: New options to set ipv4/ipv6 outbound s2s out interface
- s2s_send_packet: this hook now filters outgoing s2s stanzas
- start_room: new hook runs when a room process is started
- check_decoded_jwt: new hook to check decoded JWT after success authentication
* Admin
- Docker: Fix DB initialization
- New sql_odbc_driver option: choose the mssql ODBC driver
- Rebar3: Fully supported. Enable with ./configure --with-rebar=/path/to/rebar3
- systemd: start ejabberd in foreground
* Modules:
- MAM: Make sure that jid used as base in mam xml_compress is bare
- MAM: Support for MAM Flipped Pages
- MUC: Always show MucSub subscribers nicks
- MUC: Don't forget not-persistent rooms in load_permanent_rooms
- MUC Admin: Better error reporting
- MUC Admin: Fix commands with hibernated rooms
- MUC Admin: Many improvements in rooms_unused_list/destroy
- MUC Admin: create_room_with_opts Store options only if room starts
- Pubsub: Remove 'dag' node plugin documentation
- Push: Fix API call return type on error
- Push: Support cache config changes on reload
- Register: Allow for account-removal-only setup again
- Roster: Make roster subscriptions work better with invalid roster state in db
- Vcard: Fix vCard search by User when using Mnesia
- WebAdmin: Allow vhost admins to view WebAdmin menus
- WebAdmin: Don't do double utf-8 conversion on translated strings
- WebAdmin: Mark dangerous buttons with CSS
- WebSocket: Make websocket send put back pressure on c2s process
# Version 20.07
* Changes in this version
- Add support for using unix sockets in listeners.
- Make this version compatible with erlang R23
- Make room permissions checks more strict for subscribers
- Fix problem with muc rooms crashing when using muc logger
with some locales
- Limit stat calls that logger module issues
- Don't throw errors when using user_regexp acl rule and
having non-matching host
- Fix problem with leaving old data when updating shared rosters
- Fix edge case that caused failure of resuming old sessions with
stream management.
- Fix crash when room that was started with loging enabled was later
changed to logging disabled
- Increase default shaper limits (this should help with delays for
clients that are using jingle)
- Fix couple compatibility problems which prevented working on
erlang R19
- Fix sending presence unavailable when session terminates for
clients that only send directed presences (helps with sometimes
not leaving muc rooms on disconnect).
- Prevent supervisor errors for sockets that were closed before
they were passed to handler modules
- Make stun module work better with ipv6 addresses
# Version 20.03
* Changes in this version
+58 -34
View File
@@ -1,4 +1,4 @@
REBAR = @ESCRIPT@ rebar
REBAR = @ESCRIPT@ @rebar@
INSTALL = @INSTALL@
SED = @SED@
ERL = @ERL@
@@ -97,30 +97,50 @@ ifneq ($(INSTALLGROUP),)
G_USER=-g $(INSTALLGROUP)
endif
IS_REBAR3:=$(shell expr `$(REBAR) --version | awk -F '[ .]' '/rebar / {print $$2}'` '>=' 3)
ifeq "$(IS_REBAR3)" "1"
SKIPDEPS=
LISTDEPS=tree
UPDATEDEPS=upgrade
DEPSPATTERN="s/ (.*//; /^ / s/.* \([a-z0-9_]*\).*/\1/p;"
DEPSBASE=_build
DEPSDIR=$(DEPSBASE)/default/lib
EBINDIR=$(DEPSDIR)/ejabberd/ebin
else
SKIPDEPS=skip_deps=true
LISTDEPS=-q list-deps
UPDATEDEPS=update-deps
DEPSPATTERN="/ TAG / s/ .*// p; / REV / s/ .*// p; / BRANCH / s/ .*// p;"
DEPSBASE=deps
DEPSDIR=$(DEPSBASE)
EBINDIR=ebin
endif
all: deps src
deps: deps/.got
deps: $(DEPSDIR)/.got
deps/.got:
rm -rf deps/.got
rm -rf deps/.built
mkdir -p deps
$(REBAR) get-deps && :> deps/.got
$(DEPSDIR)/.got:
rm -rf $(DEPSDIR)/.got
rm -rf $(DEPSDIR)/.built
mkdir -p $(DEPSDIR)
$(REBAR) get-deps && :> $(DEPSDIR)/.got
deps/.built: deps/.got
$(DEPSDIR)/.built: $(DEPSDIR)/.got
$(REBAR) configure-deps
$(REBAR) compile && :> deps/.built
$(REBAR) compile && :> $(DEPSDIR)/.built
src: deps/.built
$(REBAR) skip_deps=true compile
src: $(DEPSDIR)/.built
$(REBAR) $(SKIPDEPS) compile
update:
rm -rf deps/.got
rm -rf deps/.built
$(REBAR) update-deps && :> deps/.got
rm -rf $(DEPSDIR)/.got
rm -rf $(DEPSDIR)/.built
$(REBAR) $(UPDATEDEPS) && :> $(DEPSDIR)/.got
xref: all
$(REBAR) skip_deps=true xref
$(REBAR) $(SKIPDEPS) xref
hooks: all
tools/hook_deps.sh ebin
@@ -139,10 +159,13 @@ JOIN_PATHS=$(if $(wordlist 2,1000,$(1)),$(firstword $(1))/$(call JOIN_PATHS,$(wo
VERSIONED_DEP=$(if $(DEP_$(1)_VERSION),$(DEP_$(1)_VERSION),$(1))
DEPIX:=$(words $(subst /, ,$(DEPSDIR)))
LIBIX:=$(shell expr "$(DEPIX)" + 2)
ELIXIR_TO_DEST=$(LIBDIR) $(call VERSIONED_DEP,$(word 2,$(1))) $(wordlist 5,1000,$(1))
DEPS_TO_DEST=$(LIBDIR) $(call VERSIONED_DEP,$(word 2,$(1))) $(wordlist 3,1000,$(1))
MAIN_TO_DEST=$(LIBDIR) $(call VERSIONED_DEP,ejabberd) $(1)
TO_DEST_SINGLE=$(if $(subst XdepsX,,X$(word 1,$(1))X),$(call MAIN_TO_DEST,$(1)),$(if $(subst XlibX,,X$(word 3,$(1))X),$(call DEPS_TO_DEST,$(1)),$(call ELIXIR_TO_DEST,$(1))))
TO_DEST_SINGLE=$(if $(subst X$(DEPSBASE)X,,X$(word 1,$(1))X),$(call MAIN_TO_DEST,$(1)),$(if $(subst XlibX,,X$(word $(LIBIX),$(1))X),$(call DEPS_TO_DEST,$(wordlist $(DEPIX),1000,$(1))),$(call ELIXIR_TO_DEST,$(wordlist $(DEPIX),1000,$(1)))))
TO_DEST=$(foreach path,$(1),$(call JOIN_PATHS,$(call TO_DEST_SINGLE,$(subst /, ,$(path)))))
FILTER_DIRS=$(foreach path,$(1),$(if $(wildcard $(path)/*),,$(path)))
@@ -150,16 +173,16 @@ FILES_WILDCARD=$(call FILTER_DIRS,$(foreach w,$(1),$(wildcard $(w))))
ifeq ($(MAKECMDGOALS),copy-files-sub)
DEPS:=$(sort $(shell $(REBAR) -q list-deps|$(SED) -ne '/ TAG / s/ .*// p; / REV / s/ .*// p; / BRANCH / s/ .*// p'))
DEPS:=$(sort $(shell QUIET=1 $(REBAR) $(LISTDEPS) | $(SED) -ne $(DEPSPATTERN) ))
DEPS_FILES=$(call FILES_WILDCARD,$(foreach DEP,$(DEPS),deps/$(DEP)/ebin/*.beam deps/$(DEP)/ebin/*.app deps/$(DEP)/priv/* deps/$(DEP)/priv/lib/* deps/$(DEP)/priv/bin/* deps/$(DEP)/include/*.hrl deps/$(DEP)/COPY* deps/$(DEP)/LICENSE* deps/$(DEP)/lib/*/ebin/*.beam deps/$(DEP)/lib/*/ebin/*.app))
DEPS_FILES=$(call FILES_WILDCARD,$(foreach DEP,$(DEPS),$(DEPSDIR)/$(DEP)/ebin/*.beam $(DEPSDIR)/$(DEP)/ebin/*.app $(DEPSDIR)/$(DEP)/priv/* $(DEPSDIR)/$(DEP)/priv/lib/* $(DEPSDIR)/$(DEP)/priv/bin/* $(DEPSDIR)/$(DEP)/include/*.hrl $(DEPSDIR)/$(DEP)/COPY* $(DEPSDIR)/$(DEP)/LICENSE* $(DEPSDIR)/$(DEP)/lib/*/ebin/*.beam $(DEPSDIR)/$(DEP)/lib/*/ebin/*.app))
BINARIES=deps/epam/priv/bin/epam deps/eimp/priv/bin/eimp deps/fs/priv/mac_listener
BINARIES=$(DEPSDIR)/epam/priv/bin/epam $(DEPSDIR)/eimp/priv/bin/eimp $(DEPSDIR)/fs/priv/mac_listener
DEPS_FILES_FILTERED=$(filter-out $(BINARIES) deps/elixir/ebin/elixir.app,$(DEPS_FILES))
DEPS_DIRS=$(sort deps/ $(foreach DEP,$(DEPS),deps/$(DEP)/) $(dir $(DEPS_FILES)))
DEPS_FILES_FILTERED=$(filter-out $(BINARIES) $(DEPSDIR)/elixir/ebin/elixir.app,$(DEPS_FILES))
DEPS_DIRS=$(sort $(DEPSDIR)/ $(foreach DEP,$(DEPS),$(DEPSDIR)/$(DEP)/) $(dir $(DEPS_FILES)))
MAIN_FILES=$(filter-out %/configure.beam,$(call FILES_WILDCARD,ebin/*.beam ebin/*.app priv/msgs/*.msg priv/css/*.css priv/img/*.png priv/js/*.js priv/lib/* include/*.hrl COPYING))
MAIN_FILES=$(filter-out %/configure.beam,$(call FILES_WILDCARD,$(EBINDIR)/*.beam $(EBINDIR)/*.app priv/msgs/*.msg priv/css/*.css priv/img/*.png priv/js/*.js priv/lib/* include/*.hrl COPYING))
MAIN_DIRS=$(sort $(dir $(MAIN_FILES)) priv/bin priv/sql priv/lua)
define DEP_VERSION_template
@@ -168,8 +191,8 @@ endef
DELETE_TARGET_SO=$(if $(subst X.soX,,X$(suffix $(1))X),,rm -f $(call TO_DEST,$(1));)
$(foreach DEP,$(DEPS),$(eval $(call DEP_VERSION_template,$(DEP),deps/$(DEP)/ebin/$(DEP).app)))
$(eval $(call DEP_VERSION_template,ejabberd,ebin/ejabberd.app))
$(foreach DEP,$(DEPS),$(eval $(call DEP_VERSION_template,$(DEP),$(DEPSDIR)/$(DEP)/ebin/$(DEP).app)))
$(eval $(call DEP_VERSION_template,ejabberd,$(EBINDIR)/ejabberd.app))
define COPY_template
$(call TO_DEST,$(1)): $(1) $(call TO_DEST,$(dir $(1))) ; $(call DELETE_TARGET_SO, $(1)) $$(INSTALL) -m 644 $(1) $(call TO_DEST,$(1))
@@ -206,7 +229,7 @@ copy-files:
copy-files-sub: copy-files-sub2
install: all copy-files
install: copy-files
#
# Configuration files
$(INSTALL) -d -m 750 $(G_USER) $(ETCDIR)
@@ -233,9 +256,9 @@ install: all copy-files
$(INSTALL) -m 550 $(G_USER) ejabberdctl.example $(SBINDIR)/ejabberdctl
# Elixir binaries
[ -d $(BINDIR) ] || $(INSTALL) -d -m 755 $(BINDIR)
[ -f deps/elixir/bin/iex ] && $(INSTALL) -m 550 $(G_USER) deps/elixir/bin/iex $(BINDIR)/iex || true
[ -f deps/elixir/bin/elixir ] && $(INSTALL) -m 550 $(G_USER) deps/elixir/bin/elixir $(BINDIR)/elixir || true
[ -f deps/elixir/bin/mix ] && $(INSTALL) -m 550 $(G_USER) deps/elixir/bin/mix $(BINDIR)/mix || true
[ -f $(DEPSDIR)/elixir/bin/iex ] && $(INSTALL) -m 550 $(G_USER) $(DEPSDIR)/elixir/bin/iex $(BINDIR)/iex || true
[ -f $(DEPSDIR)/elixir/bin/elixir ] && $(INSTALL) -m 550 $(G_USER) $(DEPSDIR)/elixir/bin/elixir $(BINDIR)/elixir || true
[ -f $(DEPSDIR)/elixir/bin/mix ] && $(INSTALL) -m 550 $(G_USER) $(DEPSDIR)/elixir/bin/mix $(BINDIR)/mix || true
#
# Init script
$(SED) -e "s*@ctlscriptpath@*$(SBINDIR)*g" \
@@ -311,8 +334,8 @@ uninstall-all: uninstall-binary
rm -rf $(LOGDIR)
clean:
rm -rf deps/.got
rm -rf deps/.built
rm -rf $(DEPSDIR)/.got
rm -rf $(DEPSDIR)/.built
rm -rf test/*.beam
$(REBAR) clean
@@ -323,11 +346,12 @@ distclean: clean clean-rel
rm -f config.status
rm -f config.log
rm -rf autom4te.cache
rm -rf deps
rm -rf ebin
rm -rf $(EBINDIR)
rm -rf $(DEPSBASE)
rm -f Makefile
rm -f vars.config
rm -f src/ejabberd.app.src
rm -f ejabberdctl.example ejabberd.init ejabberd.service
[ ! -f ../ChangeLog ] || rm -f ../ChangeLog
rel: all
@@ -338,7 +362,7 @@ TAGS:
Makefile: Makefile.in
deps := $(wildcard deps/*/ebin)
deps := $(wildcard $(DEPSDIR)/*/ebin)
dialyzer/erlang.plt:
@mkdir -p dialyzer
@@ -382,7 +406,7 @@ test:
@cat test/README
@echo "*************************************************************************"
@cd priv && ln -sf ../sql
$(REBAR) skip_deps=true ct
$(REBAR) $(SKIPDEPS) ct
.PHONY: src edoc dialyzer Makefile TAGS clean clean-rel distclean rel \
install uninstall uninstall-binary uninstall-all translations deps test \
+6 -6
View File
@@ -14,24 +14,24 @@ solutions very cost effectively.
Key Features
------------
- **Cross-platform**
- **Cross-platform**
ejabberd runs under Microsoft Windows and Unix-derived systems such as
Linux, FreeBSD and NetBSD.
- **Distributed**
- **Distributed**
You can run ejabberd on a cluster of machines and all of them will serve the
same XMPP domain(s). When you need more capacity you can simply add a new
cheap node to your cluster. Accordingly, you do not need to buy an expensive
high-end machine to support tens of thousands concurrent users.
- **Fault-tolerant**
- **Fault-tolerant**
You can deploy an ejabberd cluster so that all the information required for
a properly working service will be replicated permanently on all nodes. This
means that if one of the nodes crashes, the others will continue working
without disruption. In addition, nodes also can be added or replaced on
the fly.
- **Administrator-friendly**
- **Administrator-friendly**
ejabberd is built on top of the Open Source Erlang. As a result you do not
need to install an external database, an external web server, amongst others
because everything is already included, and ready to run out of the box.
@@ -46,13 +46,13 @@ Key Features
- Can integrate with existing authentication mechanisms.
- Capability to send announce messages.
- **Internationalized**
- **Internationalized**
ejabberd leads in internationalization. Hence it is very well suited in a
globalized world. Related features are:
- Translated to 25 languages.
- Support for IDNA.
- **Open Standards**
- **Open Standards**
ejabberd is the first Open Source Jabber server claiming to fully comply to
the XMPP standard.
- Fully XMPP-compliant.
+2
View File
@@ -0,0 +1,2 @@
{erl_opts, [debug_info]}.
{deps, []}.
@@ -0,0 +1,9 @@
{application, configure_deps,
[{description, "A rebar3 plugin to explicitly run configure on dependencies"},
{vsn, "0.0.1"},
{registered, []},
{applications, [kernel, stdlib]},
{env,[]},
{modules, []},
{links, []}
]}.
@@ -0,0 +1,8 @@
-module(configure_deps).
-export([init/1]).
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) ->
{ok, State1} = configure_deps_prv:init(State),
{ok, State1}.
@@ -0,0 +1,54 @@
-module(configure_deps_prv).
-export([init/1, do/1, format_error/1]).
-define(PROVIDER, 'configure-deps').
-define(DEPS, [install_deps]).
%% ===================================================================
%% Public API
%% ===================================================================
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) ->
Provider = providers:create([
{namespace, default},
{name, ?PROVIDER}, % The 'user friendly' name of the task
{module, ?MODULE}, % The module implementation of the task
{bare, true}, % The task can be run by the user, always true
{deps, ?DEPS}, % The list of dependencies
{example, "rebar3 configure-deps"}, % How to use the plugin
{opts, []}, % list of options understood by the plugin
{short_desc, "Explicitly run ./configure for dependencies"},
{desc, "A rebar plugin to allow explicitly running ./configure on depdendencies. Useful if dependencies might change prior to compilation when configure is run."}
]),
{ok, rebar_state:add_provider(State, Provider)}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
Apps = rebar_state:project_apps(State) ++ lists:usort(rebar_state:all_deps(State)),
lists:foreach(fun do_app/1, Apps),
{ok, State}.
exec_configure({'configure-deps', Cmd}, Dir) ->
rebar_utils:sh(Cmd, [{cd, Dir}, {use_stdout, true}]);
exec_configure(_, Acc) -> Acc.
parse_pre_hooks({pre_hooks, PreHooks}, Acc) ->
lists:foldl(fun exec_configure/2, Acc, PreHooks);
parse_pre_hooks(_, Acc) -> Acc.
parse_additions({add, App, Additions}, {MyApp, Dir}) when App == MyApp ->
lists:foldl(fun parse_pre_hooks/2, Dir, Additions),
{MyApp, Dir};
parse_additions(_, Acc) -> Acc.
do_app(App) ->
Dir = rebar_app_info:dir(App),
Opts = rebar_app_info:opts(App),
Overrides = rebar_opts:get(Opts, overrides),
lists:foldl(fun parse_additions/2, {binary_to_atom(rebar_app_info:name(App), utf8), Dir}, Overrides).
-spec format_error(any()) -> iolist().
format_error(Reason) ->
io_lib:format("~p", [Reason]).
-2
View File
@@ -4,9 +4,7 @@ defmodule Ejabberd.ConfigFile do
def start do
[loglevel: 4,
log_rotate_size: 10485760,
log_rotate_date: "",
log_rotate_count: 1,
log_rate_limit: 100,
auth_method: :internal,
max_fsm_queue: 1000,
language: "en",
+181 -169
View File
@@ -28,6 +28,16 @@ else
fi
])
AC_ARG_WITH(rebar,
AC_HELP_STRING([--with-rebar=bin],
[use rebar specified]),
[if test "$withval" = "yes" -o "$withval" = "no" -o "X$with_rebar" = "X"; then
rebar="rebar"
else
rebar="$with_rebar"
fi
], [rebar="rebar"])
AC_PATH_TOOL(ERL, erl, , [${extra_erl_path}$PATH])
AC_PATH_TOOL(ERLC, erlc, , [${extra_erl_path}$PATH])
AC_PATH_TOOL(EPMD, epmd, , [${extra_erl_path}$PATH])
@@ -35,18 +45,6 @@ AC_PATH_TOOL(EPMD, epmd, , [${extra_erl_path}$PATH])
AC_ERLANG_NEED_ERL
AC_ERLANG_NEED_ERLC
AC_ARG_ENABLE(erlang-version-check,
[AC_HELP_STRING([--enable-erlang-version-check],
[Check Erlang/OTP version @<:@default=yes@:>@])])
case "$enable_erlang_version_check" in
yes|'')
ERLANG_VERSION_CHECK([$REQUIRE_ERLANG_MIN],[$REQUIRE_ERLANG_MAX])
;;
no)
ERLANG_VERSION_CHECK([$REQUIRE_ERLANG_MIN],[$REQUIRE_ERLANG_MAX],[warn])
;;
esac
# Checks and sets ERLANG_ROOT_DIR and ERLANG_LIB_DIR variable
AC_ERLANG_SUBST_ROOT_DIR
# AC_ERLANG_SUBST_LIB_DIR
@@ -68,45 +66,9 @@ fi
# Change default prefix
AC_PREFIX_DEFAULT(/usr/local)
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(new_sql_schema,
[AC_HELP_STRING([--enable-new-sql-schema], [use new SQL schema (default: no)])],
[case "${enableval}" in
yes) new_sql_schema=true ;;
no) new_sql_schema=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-new-sql-schema) ;;
esac],[new_sql_schema=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_CONFIG_FILES([Makefile
vars.config
src/ejabberd.app.src])
AC_ARG_ENABLE(all,
[AC_HELP_STRING([--enable-all], [same as --enable-odbc --enable-mysql --enable-pgsql --enable-sqlite --enable-pam --enable-zlib --enable-redis --enable-elixir --enable-stun --enable-sip --enable-debug --enable-tools (useful for Dialyzer checks, default: no)])],
@@ -116,69 +78,13 @@ AC_ARG_ENABLE(all,
*) AC_MSG_ERROR(bad value ${enableval} for --enable-all) ;;
esac],[])
AC_ARG_ENABLE(tools,
[AC_HELP_STRING([--enable-tools], [build development tools (default: no)])],
AC_ARG_ENABLE(debug,
[AC_HELP_STRING([--enable-debug], [enable debug information (default: yes)])],
[case "${enableval}" in
yes) tools=true ;;
no) tools=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-tools) ;;
esac],[if test "x$tools" = "x"; then tools=false; fi])
AC_ARG_ENABLE(odbc,
[AC_HELP_STRING([--enable-odbc], [enable pure ODBC support (default: no)])],
[case "${enableval}" in
yes) odbc=true ;;
no) odbc=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-odbc) ;;
esac],[if test "x$odbc" = "x"; then odbc=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(sqlite,
[AC_HELP_STRING([--enable-sqlite], [enable SQLite support (default: no)])],
[case "${enableval}" in
yes) sqlite=true ;;
no) sqlite=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-sqlite) ;;
esac],[if test "x$sqlite" = "x"; then sqlite=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(redis,
[AC_HELP_STRING([--enable-redis], [enable Redis support (default: no)])],
[case "${enableval}" in
yes) redis=true ;;
no) redis=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-redis) ;;
esac],[if test "x$redis" = "x"; then redis=false; fi])
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(elixir,
[AC_HELP_STRING([--enable-elixir], [enable Elixir support (default: no)])],
@@ -188,63 +94,26 @@ AC_ARG_ENABLE(elixir,
*) AC_MSG_ERROR(bad value ${enableval} for --enable-elixir) ;;
esac],[if test "x$elixir" = "x"; then elixir=false; fi])
AC_ARG_ENABLE(debug,
[AC_HELP_STRING([--enable-debug], [enable debug information (default: yes)])],
AC_ARG_ENABLE(erlang-version-check,
[AC_HELP_STRING([--enable-erlang-version-check],
[Check Erlang/OTP version (default: yes)])])
case "$enable_erlang_version_check" in
yes|'')
ERLANG_VERSION_CHECK([$REQUIRE_ERLANG_MIN],[$REQUIRE_ERLANG_MAX])
;;
no)
ERLANG_VERSION_CHECK([$REQUIRE_ERLANG_MIN],[$REQUIRE_ERLANG_MAX],[warn])
;;
esac
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) debug=true ;;
no) debug=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-debug) ;;
esac],[if test "x$debug" = "x"; then debug=true; fi])
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(latest_deps,
[AC_HELP_STRING([--enable-latest-deps], [makes rebar use latest commits for dependences instead of tagged versions (default: no)])],
[case "${enableval}" in
yes) latest_deps=true ;;
no) latest_deps=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-latest-deps) ;;
esac],[if test "x$latest_deps" = "x"; then latest_deps=false; fi])
AC_ARG_ENABLE(system_deps,
[AC_HELP_STRING([--enable-system-deps], [makes rebar use localy installed dependences instead of downloading them (default: no)])],
[case "${enableval}" in
yes) system_deps=true ;;
no) system_deps=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-system-deps) ;;
esac],[if test "x$system_deps" = "x"; then system_deps=false; fi])
AC_ARG_ENABLE(stun,
[AC_HELP_STRING([--enable-stun], [enable STUN/TURN 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(sip,
[AC_HELP_STRING([--enable-sip], [enable SIP support (default: no)])],
[case "${enableval}" in
yes) sip=true ;;
no) sip=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-sip) ;;
esac],[if test "x$sip" = "x"; then sip=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
ENABLEGROUP=""
AC_ARG_ENABLE(group,
[AS_HELP_STRING([--enable-group[[[[=GROUP]]]]], [allow this system group to start ejabberd (default: no)])],
@@ -259,6 +128,148 @@ if test "$ENABLEGROUP" != ""; then
AC_SUBST([INSTALLGROUP], [$ENABLEGROUP])
fi
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(latest_deps,
[AC_HELP_STRING([--enable-latest-deps], [makes rebar use latest commits for dependencies instead of tagged versions (default: no)])],
[case "${enableval}" in
yes) latest_deps=true ;;
no) latest_deps=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-latest-deps) ;;
esac],[if test "x$latest_deps" = "x"; then latest_deps=false; fi])
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; mssql=true ;;
no) db_type=generic; mssql=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-mssql) ;;
esac],[db_type=generic])
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(new_sql_schema,
[AC_HELP_STRING([--enable-new-sql-schema], [use new SQL schema (default: no)])],
[case "${enableval}" in
yes) new_sql_schema=true ;;
no) new_sql_schema=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-new-sql-schema) ;;
esac],[new_sql_schema=false])
AC_ARG_ENABLE(odbc,
[AC_HELP_STRING([--enable-odbc], [enable pure ODBC support (default: no)])],
[case "${enableval}" in
yes) odbc=true ;;
no) odbc=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-odbc) ;;
esac],[if test "x$odbc" = "x"; then odbc=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(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(redis,
[AC_HELP_STRING([--enable-redis], [enable Redis support (default: no)])],
[case "${enableval}" in
yes) redis=true ;;
no) redis=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-redis) ;;
esac],[if test "x$redis" = "x"; then redis=false; fi])
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(sip,
[AC_HELP_STRING([--enable-sip], [enable SIP support (default: no)])],
[case "${enableval}" in
yes) sip=true ;;
no) sip=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-sip) ;;
esac],[if test "x$sip" = "x"; then sip=false; fi])
AC_ARG_ENABLE(sqlite,
[AC_HELP_STRING([--enable-sqlite], [enable SQLite support (default: no)])],
[case "${enableval}" in
yes) sqlite=true ;;
no) sqlite=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-sqlite) ;;
esac],[if test "x$sqlite" = "x"; then sqlite=false; fi])
AC_ARG_ENABLE(stun,
[AC_HELP_STRING([--enable-stun], [enable STUN/TURN support (default: yes)])],
[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=true; fi])
AC_ARG_ENABLE(system_deps,
[AC_HELP_STRING([--enable-system-deps], [makes rebar use locally installed dependencies instead of downloading them (default: no)])],
[case "${enableval}" in
yes) system_deps=true ;;
no) system_deps=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-system-deps) ;;
esac],[if test "x$system_deps" = "x"; then system_deps=false; fi])
AC_ARG_ENABLE(tools,
[AC_HELP_STRING([--enable-tools], [build development tools (default: no)])],
[case "${enableval}" in
yes) tools=true ;;
no) tools=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-tools) ;;
esac],[if test "x$tools" = "x"; then tools=false; fi])
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_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])
if test "$sqlite" = "true"; then
AX_LIB_SQLITE3([3.6.19])
if test "x$SQLITE3_VERSION" = "x"; then
@@ -267,7 +278,7 @@ if test "$sqlite" = "true"; then
fi
enabled_backends=""
for backend in odbc mysql pgsql sqlite redis; do
for backend in odbc mysql pgsql sqlite redis mssql; do
if eval test x\${$backend} = xtrue; then
if test "x$enabled_backends" = "x"; then
enabled_backends=$backend
@@ -288,6 +299,7 @@ AC_SUBST(pgsql)
AC_SUBST(sqlite)
AC_SUBST(pam)
AC_SUBST(zlib)
AC_SUBST(rebar)
AC_SUBST(redis)
AC_SUBST(elixir)
AC_SUBST(stun)
+1 -2
View File
@@ -3,13 +3,12 @@ Description=XMPP Server
After=network.target
[Service]
Type=forking
User=ejabberd
Group=ejabberd
LimitNOFILE=65536
Restart=on-failure
RestartSec=5
ExecStart=/bin/sh -c '@ctlscriptpath@/ejabberdctl start && @ctlscriptpath@/ejabberdctl started'
ExecStart=@ctlscriptpath@/ejabberdctl foreground
ExecStop=/bin/sh -c '@ctlscriptpath@/ejabberdctl stop && @ctlscriptpath@/ejabberdctl stopped'
ExecReload=@ctlscriptpath@/ejabberdctl reload_config
PrivateDevices=true
+23 -6
View File
@@ -57,6 +57,16 @@ listen:
request_handlers:
/admin: ejabberd_web_admin
/.well-known/acme-challenge: ejabberd_acme
-
port: 3478
ip: "::"
transport: udp
module: ejabberd_stun
use_turn: true
## The server's public IPv4 address:
# turn_ipv4_address: "203.0.113.3"
## The server's public IPv6 address:
# turn_ipv6_address: "2001:db8::3"
-
port: 1883
ip: "::"
@@ -100,14 +110,14 @@ api_permissions:
who:
access:
allow:
acl: loopback
acl: admin
- acl: loopback
- acl: admin
oauth:
scope: "ejabberd:admin"
access:
allow:
acl: loopback
acl: admin
- acl: loopback
- acl: admin
what:
- "*"
- "!stop"
@@ -120,8 +130,10 @@ api_permissions:
- connected_users_number
shaper:
normal: 1000
fast: 50000
normal:
rate: 3000
burst_size: 20000
fast: 100000
shaper_rules:
max_user_sessions: 10
@@ -150,6 +162,10 @@ modules:
mod_http_api: {}
mod_http_upload:
put_url: https://@HOST@:5443/upload
custom_headers:
"Access-Control-Allow-Origin": "https://@HOST@"
"Access-Control-Allow-Methods": "GET,HEAD,PUT,OPTIONS"
"Access-Control-Allow-Headers": "Content-Type"
mod_last: {}
mod_mam:
## Mnesia is limited to 2GB, better to use an SQL backend
@@ -203,6 +219,7 @@ modules:
mod_shared_roster: {}
mod_stream_mgmt:
resend_on_timeout: if_offline
mod_stun_disco: {}
mod_vcard: {}
mod_vcard_xupdate: {}
mod_version:
-2
View File
@@ -63,8 +63,6 @@
#.
#' ERL_EPMD_ADDRESS: IP addresses where epmd listens for connections
#
# IMPORTANT: This option works only in Erlang/OTP R14B03 and newer.
#
# This environment variable may be set to a comma-separated
# list of IP addresses, in which case the epmd daemon
# will listen only on the specified address(es) and on the
+14 -4
View File
@@ -60,6 +60,8 @@ done
: "${SPOOL_DIR:="{{localstatedir}}/lib/ejabberd"}"
: "${EJABBERD_CONFIG_PATH:="$ETC_DIR/ejabberd.yml"}"
: "${EJABBERDCTL_CONFIG_PATH:="$ETC_DIR/ejabberdctl.cfg"}"
# Allows passing extra Erlang command-line arguments in vm.args file
: "${VMARGS:="$ETC_DIR/vm.args"}"
[ -f "$EJABBERDCTL_CONFIG_PATH" ] && . "$EJABBERDCTL_CONFIG_PATH"
[ -n "$ERLANG_NODE_ARG" ] && ERLANG_NODE="$ERLANG_NODE_ARG"
[ "$ERLANG_NODE" = "${ERLANG_NODE%.*}" ] && S="-s"
@@ -77,16 +79,16 @@ if [ -n "$INET_DIST_INTERFACE" ] ; then
ERLANG_OPTS="$ERLANG_OPTS -kernel inet_dist_use_interface $INET_DIST_INTERFACE2"
fi
fi
# if vm.args file exists in config directory, pass it to Erlang VM
[ -f "$VMARGS" ] && ERLANG_OPTS="$ERLANG_OPTS -args_file $VMARGS"
ERL_LIBS={{libdir}}
ERL_CRASH_DUMP="$LOGS_DIR"/erl_crash_$(date "+%Y%m%d-%H%M%S").dump
ERL_INETRC="$ETC_DIR"/inetrc
# define ejabberd parameters
EJABBERD_OPTS="$EJABBERD_OPTS\
$(sed '/^log_rate_limit/!d;s/:[ \t]*\([0-9]*\).*/ \1/;s/^/ /' "$EJABBERD_CONFIG_PATH")\
$(sed '/^log_rotate_size/!d;s/:[ \t]*\([0-9]*\).*/ \1/;s/^/ /' "$EJABBERD_CONFIG_PATH")\
$(sed '/^log_rotate_count/!d;s/:[ \t]*\([0-9]*\).*/ \1/;s/^/ /' "$EJABBERD_CONFIG_PATH")\
$(sed '/^log_rotate_date/!d;s/:[ \t]*\(.[^ ]*\).*/ \1/;s/^/ /' "$EJABBERD_CONFIG_PATH")"
$(sed '/^log_rotate_count/!d;s/:[ \t]*\([0-9]*\).*/ \1/;s/^/ /' "$EJABBERD_CONFIG_PATH")"
[ -n "$EJABBERD_OPTS" ] && EJABBERD_OPTS="-ejabberd $EJABBERD_OPTS"
EJABBERD_OPTS="-mnesia dir \"$SPOOL_DIR\" $MNESIA_OPTIONS $EJABBERD_OPTS -s ejabberd"
@@ -126,6 +128,14 @@ exec_iex()
# usage
debugwarning()
{
if [ "$OSTYPE" != "cygwin" ] && [ "$OSTYPE" != "win32" ] ; then
if [ "a$TERM" = "a" ] || [ "$TERM" = "dumb" ] ; then
echo "Terminal type not supported."
echo "You may have to set the TERM environment variable to fix this."
exit 8
fi
fi
if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then
echo "--------------------------------------------------------------------"
echo ""
@@ -198,7 +208,7 @@ uid()
uuid=$(uuidgen 2>/dev/null)
[ -z "$uuid" ] && [ -f /proc/sys/kernel/random/uuid ] && uuid=$(cat /proc/sys/kernel/random/uuid)
[ -z "$uuid" ] && uuid=$(printf "%X" "${RANDOM:-$$}$(date +%M%S)")
uuid=${uuid%%-*}
uuid=$(printf '%s' $uuid | sed 's/^\(...\).*$/\1/')
[ $# -eq 0 ] && echo "${uuid}-${ERLANG_NODE}"
[ $# -eq 1 ] && echo "${uuid}-${1}-${ERLANG_NODE}"
[ $# -eq 2 ] && echo "${uuid}-${1}@${2}"
+1
View File
@@ -21,6 +21,7 @@
-record(request,
{method :: method(),
path = [] :: [binary()],
raw_path :: binary(),
q = [] :: [{binary() | nokey, binary()}],
us = {<<>>, <<>>} :: {binary(), binary()},
auth :: {binary(), binary()} | {oauth, binary(), []} | undefined | invalid,
+10 -2
View File
@@ -65,6 +65,14 @@
-define(INPUTT(Type, Name, Value),
?INPUT(Type, Name, (translate:translate(Lang, Value)))).
-define(INPUTD(Type, Name, Value),
?XA(<<"input">>,
[{<<"type">>, Type}, {<<"name">>, Name},
{<<"class">>, <<"btn-danger">>}, {<<"value">>, Value}])).
-define(INPUTTD(Type, Name, Value),
?INPUTD(Type, Name, (translate:translate(Lang, Value)))).
-define(INPUTS(Type, Name, Value, Size),
?XA(<<"input">>,
[{<<"type">>, Type}, {<<"name">>, Name},
@@ -93,9 +101,9 @@
-define(GL(Ref, Title),
?XAE(<<"div">>, [{<<"class">>, <<"guidelink">>}],
[?XAE(<<"a">>,
[{<<"href">>, <<"https://docs.ejabberd.im/admin/configuration/#", Ref/binary>>},
[{<<"href">>, <<"https://docs.ejabberd.im/admin/configuration/", Ref/binary>>},
{<<"target">>, <<"_blank">>}],
[?C(<<"[Guide: ", Title/binary, "]">>)])])).
[?C(<<"docs: ", Title/binary>>)])])).
%% h1 with a Guide Link
-define(H1GL(Name, Ref, Title),
+1178 -74
View File
File diff suppressed because it is too large Load Diff
+9 -6
View File
@@ -3,7 +3,7 @@ defmodule Ejabberd.Mixfile do
def project do
[app: :ejabberd,
version: "20.3.0",
version: "20.12.0",
description: description(),
elixir: "~> 1.4",
elixirc_paths: ["lib"],
@@ -66,7 +66,10 @@ defmodule Ejabberd.Mixfile do
cond_options() ++
Enum.map(includes, fn (path) -> {:i, path} end) ++
if_version_above('20', [{:d, :DEPRECATED_GET_STACKTRACE}]) ++
if_version_below('21', [{:d, :USE_OLD_HTTP_URI}]) ++
if_version_below('22', [{:d, :LAGER}]) ++
if_version_below('23', [{:d, :USE_OLD_CRYPTO_HMAC}]) ++
if_version_below('23', [{:d, :USE_OLD_PG2}]) ++
if_function_exported(:erl_error, :format_exception, 6, [{:d, :HAVE_ERL_ERROR}])
defines = for {:d, value} <- result, do: {:d, value}
result ++ [{:d, :ALL_DEFS, defines}]
@@ -85,17 +88,17 @@ defmodule Ejabberd.Mixfile do
[{:lager, "~> 3.6.0"},
{:p1_utils, "~> 1.0"},
{:fast_xml, "~> 1.1"},
{:xmpp, "~> 1.4"},
{:xmpp, ">= 1.5.0"},
{:cache_tab, "~> 1.0"},
{:stringprep, "~> 1.0"},
{:fast_yaml, "~> 1.0"},
{:fast_tls, "~> 1.1"},
{:stun, "~> 1.0"},
{:esip, "~> 1.0"},
{:stun, "~> 1.0.34"},
{:esip, "~> 1.0.32"},
{:p1_mysql, "~> 1.0"},
{:mqtree, "~> 1.0"},
{:p1_pgsql, "~> 1.1"},
{:jiffy, "~> 1.0"},
{:jiffy, "~> 1.0.4"},
{:p1_oauth2, "~> 0.6.1"},
{:distillery, "~> 2.0"},
{:pkix, "~> 1.0"},
@@ -142,7 +145,7 @@ defmodule Ejabberd.Mixfile do
defp package do
[# These are the default files included in the package
files: ["lib", "src", "priv", "mix.exs", "include", "README.md", "COPYING"],
files: ["lib", "src", "priv", "mix.exs", "include", "README.md", "COPYING", "rebar.config", "rebar.config.script"],
maintainers: ["ProcessOne"],
licenses: ["GPLv2"],
links: %{"Site" => "https://www.ejabberd.im",
+28 -27
View File
@@ -1,38 +1,39 @@
%{
"artificery": {:hex, :artificery, "0.4.2", "3ded6e29e13113af52811c72f414d1e88f711410cac1b619ab3a2666bbd7efd4", [:mix], [], "hexpm", "514586f4312ef3709a3ccbd8e55f69455add235c1729656687bb781d10d0afdb"},
"artificery": {:hex, :artificery, "0.4.3", "0bc4260f988dcb9dda4b23f9fc3c6c8b99a6220a331534fdf5bf2fd0d4333b02", [:mix], [], "hexpm", "12e95333a30e20884e937abdbefa3e7f5e05609c2ba8cf37b33f000b9ffc0504"},
"base64url": {:hex, :base64url, "0.0.1", "36a90125f5948e3afd7be97662a1504b934dd5dac78451ca6e9abf85a10286be", [:rebar], [], "hexpm", "fab09b20e3f5db886725544cbcf875b8e73ec93363954eb8a1a9ed834aa8c1f9"},
"cache_tab": {:hex, :cache_tab, "1.0.22", "ad16577e7f26709cacdcb86e6a4960c8d158cab9d189cdf49cc1e2dc33106a70", [:rebar3], [{:p1_utils, "1.0.18", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "53ed75e7c289434953a4407eb0a40b8675c5046b057313f97cf10e196efd8d79"},
"cache_tab": {:hex, :cache_tab, "1.0.26", "6f6086ac80b797f54a68773d9d782e054877e217f8f1e2fbc6deb1557cc3e26a", [:rebar3], [{:p1_utils, "1.0.21", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "a7f0a03e3a9d6275e4a7583a1f3088e6764dd1e362464eaa8e2fcca9c3b235c3"},
"distillery": {:hex, :distillery, "2.1.1", "f9332afc2eec8a1a2b86f22429e068ef35f84a93ea1718265e740d90dd367814", [:mix], [{:artificery, "~> 0.2", [hex: :artificery, repo: "hexpm", optional: false]}], "hexpm", "bbc7008b0161a6f130d8d903b5b3232351fccc9c31a991f8fcbf2a12ace22995"},
"earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm", "8cf8a291ebf1c7b9539e3cddb19e9cef066c2441b1640f13c34c1d3cfc825fec"},
"eimp": {:hex, :eimp, "1.0.14", "fc297f0c7e2700457a95a60c7010a5f1dcb768a083b6d53f49cd94ab95a28f22", [:rebar3], [{:p1_utils, "1.0.18", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "501133f3112079b92d9e22da8b88bf4f0e13d4d67ae9c15c42c30bd25ceb83b6"},
"epam": {:hex, :epam, "1.0.6", "6e57e1f5a330fa02a08ee0d4b16d9161f95177351e48c6dfede2f89b7e2f589f", [:rebar3], [], "hexpm"},
"earmark_parser": {:hex, :earmark_parser, "1.4.12", "b245e875ec0a311a342320da0551da407d9d2b65d98f7a9597ae078615af3449", [:mix], [], "hexpm", "711e2cc4d64abb7d566d43f54b78f7dc129308a63bc103fbd88550d2174b3160"},
"eimp": {:hex, :eimp, "1.0.18", "b6532f90c87741bebdfe62582e2c70caafa1337c3aa7fb85daaba3e9bad4b8a0", [:rebar3], [{:p1_utils, "1.0.21", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "7df78b25d7c325fe6c4d77901013be2f4341f4207bc7a985fea00a1bea15dd3a"},
"epam": {:hex, :epam, "1.0.7", "55889bbfdc5ab9f2e785a710229f34e550784c5ead1960d7839ea77514aef44d", [:rebar3], [], "hexpm", "6b029ebd2b244bc339cbf5cb5908d0f2d50e43f33a6e7f70818912ea5d3fd596"},
"eredis": {:hex, :eredis, "1.2.0", "0b8e9cfc2c00fa1374cd107ea63b49be08d933df2cf175e6a89b73dd9c380de4", [:rebar3], [], "hexpm"},
"esip": {:hex, :esip, "1.0.32", "b6d5d9eb8342b86509de02ac79e6a9a772dab011e936092441d4e92a7986ca29", [:rebar3], [{:fast_tls, "1.1.4", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.18", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stun, "1.0.31", [hex: :stun, repo: "hexpm", optional: false]}], "hexpm", "ab083aaa144c718d5f1c06b3034947cf6a9f73aedca04015813c983478ad94ed"},
"ex_doc": {:hex, :ex_doc, "0.21.3", "857ec876b35a587c5d9148a2512e952e24c24345552259464b98bfbb883c7b42", [:mix], [{:earmark, "~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "0db1ee8d1547ab4877c5b5dffc6604ef9454e189928d5ba8967d4a58a801f161"},
"ezlib": {:hex, :ezlib, "1.0.7", "c8adffd32e66831df77955d163d705cdcf0a3d66762e6f68f8123012e714bf05", [:rebar3], [], "hexpm", "5634b9f7112837f9338a61da1993601f4ab81615de84ff0baddcdc5a3fe940dc"},
"fast_tls": {:hex, :fast_tls, "1.1.4", "a0320baf14be72fc9f99211543e411bb98077bf72c42e2d86fc4e2c10d60c258", [:rebar3], [{:p1_utils, "1.0.18", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "027fc2a726d6f3ad36c7fa230780000e8d3fc72dc8b397c9bff2018d3f5ff06a"},
"fast_xml": {:hex, :fast_xml, "1.1.39", "687080c0190a8c45d564a3576201f1a89f31ae413dd700a2def0821736f98d4d", [:rebar3], [{:p1_utils, "1.0.18", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "2521816ed30b9c76befd85e477b5173c0329bd08fc8429f970b668c14bddb3f9"},
"fast_yaml": {:hex, :fast_yaml, "1.0.24", "d304799e6b961a21a509449830193154870b2b526cfc2e7046e9953ad413765f", [:rebar3], [{:p1_utils, "1.0.18", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "71f4d5f868a2cfd4794e6bbd89495c4e4c54c45c6cb65b7f12d96271d6c02c84"},
"esip": {:hex, :esip, "1.0.39", "ec7705f685df1f9957bb7883c65e959e27b46899a9c9fa7f79e67919fc3e2bbb", [:rebar3], [{:fast_tls, "1.1.10", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.21", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stun, "1.0.40", [hex: :stun, repo: "hexpm", optional: false]}], "hexpm", "08f4cfe69e88d60ebbe5ccdaa36fe4f3411086832a19876497972747e089a076"},
"ex_doc": {:hex, :ex_doc, "0.23.0", "a069bc9b0bf8efe323ecde8c0d62afc13d308b1fa3d228b65bca5cf8703a529d", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "f5e2c4702468b2fd11b10d39416ddadd2fcdd173ba2a0285ebd92c39827a5a16"},
"ezlib": {:hex, :ezlib, "1.0.9", "b17136b48bcf73962446b06d4427b0b6f2be4550bb5190a18a2979640271e244", [:rebar3], [], "hexpm", "fafc60a0de6e982be38f793da7b220b87a0da2969eba8a878351442b35cc2fde"},
"fast_tls": {:hex, :fast_tls, "1.1.10", "c2a14d66d73b589c6d06841f72433611bf0360953b2e9164b1435d045bf1944d", [:rebar3], [{:p1_utils, "1.0.21", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "17fb7dac5f64b9215b57e5315f4eafd682520d5a821b5b49cbe204882375bb85"},
"fast_xml": {:hex, :fast_xml, "1.1.45", "68eeec9a3c5e58de9164dd288523822226955d97013bd8a4d7657cf622eeb076", [:rebar3], [{:p1_utils, "1.0.21", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "2d8eb7bb642920e63f69501b7bdb596bef135fc4919d9b6895875fa88d8a63e0"},
"fast_yaml": {:hex, :fast_yaml, "1.0.29", "02203981b9a387321a88676e8a501935df0d5d95c6b1d08c864fb9a7657c3b5b", [:rebar3], [{:p1_utils, "1.0.21", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "b6e9ed0203f40079d2c14df6f8ab9dcfdc4a71e023cfb6de732b8d3081084b10"},
"goldrush": {:hex, :goldrush, "0.1.9", "f06e5d5f1277da5c413e84d5a2924174182fb108dabb39d5ec548b27424cd106", [:rebar3], [], "hexpm", "99cb4128cffcb3227581e5d4d803d5413fa643f4eb96523f77d9e6937d994ceb"},
"idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "4bdd305eb64e18b0273864920695cb18d7a2021f31a11b9c5fbcd9a253f936e2"},
"jiffy": {:hex, :jiffy, "1.0.1", "4f25639772ca41202f41ba9c8f6ca0933554283dd4742c90651e03471c55e341", [:rebar3], [], "hexpm", "2568927f6f5e383cb775f6fd87bc6e80ea5f7d813418de450aa644b02c7f7112"},
"jiffy": {:hex, :jiffy, "1.0.4", "72adeff75c52a2ff07de738f0813768abe7ce158026cc1115a170340259c0caa", [:rebar3], [], "hexpm", "113e5299ee4e6b9f40204256d7bbbd1caf646edeaef31ef0f7f5f842c0dad39e"},
"jose": {:hex, :jose, "1.9.0", "4167c5f6d06ffaebffd15cdb8da61a108445ef5e85ab8f5a7ad926fdf3ada154", [:mix, :rebar3], [{:base64url, "~> 0.0.1", [hex: :base64url, repo: "hexpm", optional: false]}], "hexpm", "6429c4fee52b2dda7861ee19a4f09c8c1ffa213bee3a1ec187828fde95d447ed"},
"lager": {:hex, :lager, "3.6.10", "6172b43ab720ac33914ccd0aeb21fdbdf88213847707d4b91e6af57b2ae5c4d2", [:rebar3], [{:goldrush, "0.1.9", [hex: :goldrush, repo: "hexpm", optional: false]}], "hexpm", "5d10499461826b79c5abee18bb594b3949cbdf76d9d9fd7e66d0a558137c21c9"},
"luerl": {:hex, :luerl, "0.3.1", "5412807630aac1aaf59ffe5a1bc09259c447b4faeb1d3fe2d4ef41b87676cb04", [:rebar3], [], "hexpm"},
"makeup": {:hex, :makeup, "1.0.0", "671df94cf5a594b739ce03b0d0316aa64312cee2574b6a44becb83cd90fb05dc", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a10c6eb62cca416019663129699769f0c2ccf39428b3bb3c0cb38c718a0c186d"},
"makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "d4b316c7222a85bbaa2fd7c6e90e37e953257ad196dc229505137c5e505e9eff"},
"mqtree": {:hex, :mqtree, "1.0.7", "0d8f6101eb2bb6a6e27f0e5a60cfad04b27dd552e75f30294e565605ce7cd0d2", [:rebar3], [{:p1_utils, "1.0.18", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "317db0349a8d9695bc89ef7062e9654e93347cd9576f827739650e26482825bb"},
"nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm", "589b5af56f4afca65217a1f3eb3fee7e79b09c40c742fddc1c312b3ac0b3399f"},
"p1_acme": {:hex, :p1_acme, "1.0.5", "de54353100ed82d0c820fbc011b7a7ad54f65af052eb8112922ad8be8eadf8f1", [:rebar3], [{:idna, "~>6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:jiffy, "~>1.0.1", [hex: :jiffy, repo: "hexpm", optional: false]}, {:jose, "~>1.9.0", [hex: :jose, repo: "hexpm", optional: false]}, {:yconf, "~>1.0.4", [hex: :yconf, repo: "hexpm", optional: false]}], "hexpm", "cbecfc70ce11d37d679875117c685aa2a7bc2502bfa51722c8e619602c92a0c0"},
"p1_mysql": {:hex, :p1_mysql, "1.0.14", "ea2d58d0551d62fce9882f65fc7e0273ae6d683ab277aad657a661f514411198", [:rebar3], [], "hexpm", "70df0680b71118ace166e59fbf8be19058be3c3918bc3b7ede6e1f297a4a9dbe"},
"p1_oauth2": {:hex, :p1_oauth2, "0.6.6", "b17053bd7a34621f9a1a7327285a3e37abd38eb1d176afccc8cfc39882ff0a44", [:rebar3], [], "hexpm", "8a5fd16fc581a50e62176ab8b78b83b6e7cc6f76f7f59f75f58d713b7c1ca7b2"},
"p1_pgsql": {:hex, :p1_pgsql, "1.1.9", "07ff9b037954dec06b4e30e33a82ac69a5a513e2860d2e59b7f6f4af23493c45", [:rebar3], [], "hexpm", "81aab8cff0203250dd3d9cc77a0232dc9f8e56c99fd742abbaedc51a0fd633a7"},
"p1_utils": {:hex, :p1_utils, "1.0.18", "3fe224de5b2e190d730a3c5da9d6e8540c96484cf4b4692921d1e28f0c32b01c", [:rebar3], [], "hexpm", "1fc8773a71a15553b179c986b22fbeead19b28fe486c332d4929700ffeb71f88"},
"pkix": {:hex, :pkix, "1.0.5", "407c02c70191d0791cd9b422ac2380df5f7f8304ec26a6d3b06e0e02be688fca", [:rebar3], [], "hexpm", "b86aed212afaf019ac97bf56857366e5f01c3003f38ee050af8ba16455e13719"},
"sqlite3": {:hex, :sqlite3, "1.1.6", "4ea71af0b45908b5f02c9b09e4c87177039ef404f20accb35049cd8924cc417c", [:rebar3], [], "hexpm"},
"stringprep": {:hex, :stringprep, "1.0.19", "79761de42960a625fb0cd6d31686f6118aef30540a7abb884b92f72861b6adde", [:rebar3], [{:p1_utils, "1.0.18", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "3f77edbcb530899faffe95d57b6e2bac704a5a6ea1ead5957387f9e4ed8c5f07"},
"stun": {:hex, :stun, "1.0.31", "577d845d4b77b155bad234598c2056f6e182f178468727de083bedf275dc83a1", [:rebar3], [{:fast_tls, "1.1.4", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.18", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "c7edd93d823c0e1438bfe70adf99c39cf4cbca73cbd3c086c6e461ad00c6f8d4"},
"luerl": {:hex, :luerl, "0.3.1", "5412807630aac1aaf59ffe5a1bc09259c447b4faeb1d3fe2d4ef41b87676cb04", [:rebar3], [], "hexpm", "1bc011c7297e43aec762e53b17ecb15b0ff29f9546cd153110b343cf5b043f5f"},
"makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"},
"makeup_elixir": {:hex, :makeup_elixir, "0.15.0", "98312c9f0d3730fde4049985a1105da5155bfe5c11e47bdc7406d88e01e4219b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "75ffa34ab1056b7e24844c90bfc62aaf6f3a37a15faa76b07bc5eba27e4a8b4a"},
"mqtree": {:hex, :mqtree, "1.0.11", "8ea161bd2075cb23840bb4ebc94d33d08e110c82d0771b0482e022e1b7e3377a", [:rebar3], [{:p1_utils, "1.0.21", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "975a8514ce14550ae945f7c297d2b12269dbfa69db410320163718ad42229adf"},
"nimble_parsec": {:hex, :nimble_parsec, "1.1.0", "3a6fca1550363552e54c216debb6a9e95bd8d32348938e13de5eda962c0d7f89", [:mix], [], "hexpm", "08eb32d66b706e913ff748f11694b17981c0b04a33ef470e33e11b3d3ac8f54b"},
"p1_acme": {:hex, :p1_acme, "1.0.6", "0b007b776331e3d6effe700fa85d63236a98dc4e6e8c3abbbf816d1bec70df3f", [:rebar3], [{:idna, "~>6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:jiffy, "~>1.0.1", [hex: :jiffy, repo: "hexpm", optional: false]}, {:jose, "~>1.9.0", [hex: :jose, repo: "hexpm", optional: false]}, {:yconf, "~>1.0.5", [hex: :yconf, repo: "hexpm", optional: false]}], "hexpm", "7cc6528cbbe7a98929e954604ec670de56ca9f7a69a14d22166e8746fbe86f10"},
"p1_mysql": {:hex, :p1_mysql, "1.0.17", "1fd1eed07a0f1e79851e7a5dc17995ba42af1c1192dff978d5f17c9e096a6d8c", [:rebar3], [], "hexpm", "7da95ba3f36e50e80f6a7f89a0928c0bbe6c0a8c8a7a7432d1aa7349e5964a59"},
"p1_oauth2": {:hex, :p1_oauth2, "0.6.8", "22b859f3694da30c45722fae860922150f74cfb149ef6176a67c514093238917", [:rebar3], [], "hexpm", "12a476d809f3123098948ee95676198008e96afbc433070a1382e5aa3d2a7b93"},
"p1_pgsql": {:hex, :p1_pgsql, "1.1.10", "e4b19c9768ef4047f9c56090a91bfefc7337abb3809a28aa4a6538eef6ad76b0", [:rebar3], [], "hexpm", "5458c0db9e47425f8cc1f592356a29359267c624785b316b34a46ad7439e9367"},
"p1_utils": {:hex, :p1_utils, "1.0.21", "9d6244bbd4af881e85af71655e8be5720b5b965b1bdd51a35c7871fd4142af9a", [:rebar3], [], "hexpm", "4b9b90e5863f5fed17f06427ba99b2dc37b216e4dd1308891f0903745e2fccbd"},
"pkix": {:hex, :pkix, "1.0.7", "a0b8c9011edeba702d7cb73fecef1eabe3ae89b3dcf4b8f33775e4f17a7a1304", [:rebar3], [], "hexpm", "104a9e0ecd9cc0e579d148a028189a6efe6420b241f3d319d8a65d898a078295"},
"sqlite3": {:hex, :sqlite3, "1.1.6", "4ea71af0b45908b5f02c9b09e4c87177039ef404f20accb35049cd8924cc417c", [:rebar3], [], "hexpm", "cf9fa59c5b27de0d5d94a2ef464521379e23d8c6e9fa939abf8415c767f514bb"},
"stringprep": {:hex, :stringprep, "1.0.24", "5a2c29785cdc1eaddcba0564cd86020e5e686fe9e66fa47a80a97333f3dc75ea", [:rebar3], [{:p1_utils, "1.0.21", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "aed7ac217493e5aa2f76066fb7bbfe0d4e94ca1ee72613dc954231422d911266"},
"stun": {:hex, :stun, "1.0.40", "9cc25f667f4d36321a259521c3f4848a53bfebed989cf3d761790447daeec41d", [:rebar3], [{:fast_tls, "1.1.10", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.21", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "46073f5a05a5d6ca9de1339be990600648228c204b9a690f1b5f5dfd5a895b6a"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm", "1d1848c40487cdb0b30e8ed975e34e025860c02e419cb615d255849f3427439d"},
"xmpp": {:hex, :xmpp, "1.4.5", "b226baa9ad960e8de041289b94bbcb6148a7980acc0c1ec58dfc8f24acded3ad", [:rebar3], [{:ezlib, "1.0.7", [hex: :ezlib, repo: "hexpm", optional: false]}, {:fast_tls, "1.1.4", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:fast_xml, "1.1.39", [hex: :fast_xml, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.18", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stringprep, "1.0.19", [hex: :stringprep, repo: "hexpm", optional: false]}], "hexpm", "7bd21dd10ff3369f65128fcf730595073f1b6288a8b563d165874aecb2220317"},
"yconf": {:hex, :yconf, "1.0.4", "f08dcc2ad041f68580e98753f70453976d256f2c1a40a29a985465ab16d489a6", [:rebar3], [{:fast_yaml, "1.0.24", [hex: :fast_yaml, repo: "hexpm", optional: false]}], "hexpm", "44570111ad224ee4eec6e2bffa1e7223ef4b76f91f9dd2f768eee214d2dcabe2"},
"xmpp": {:hex, :xmpp, "1.5.0", "23b5b43e1858a5f6c53e204904ef8fb41d0f2419290bcd044fb7dc313fa2e689", [:rebar3], [{:ezlib, "1.0.9", [hex: :ezlib, repo: "hexpm", optional: false]}, {:fast_tls, "1.1.10", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:fast_xml, "1.1.45", [hex: :fast_xml, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.21", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stringprep, "1.0.24", [hex: :stringprep, repo: "hexpm", optional: false]}], "hexpm", "4be95acc98ce3e6b0c67873a14a6f7d6db0fd131d77ccc4d4243f77b12f2945f"},
"yconf": {:hex, :yconf, "1.0.9", "32e922e47c3b18b1fa6f7502bfb433d3419e038123982fe7e478f3eb5d9aff0c", [:rebar3], [{:fast_yaml, "1.0.29", [hex: :fast_yaml, repo: "hexpm", optional: false]}], "hexpm", "97ab7b889f92f65447ed2db485324aba382447fa4ce8b57e466ab994da5f6233"},
}
+8 -1
View File
@@ -243,7 +243,6 @@ p[dir=ltr] a {
background: #3eaffa;
text-transform: uppercase;
font-size: 0.75em;
color: #fff;
}
@@ -277,3 +276,11 @@ p.result {
*.alignright {
text-align: right;
}
.btn-danger:hover {
color: #fff;
background-color: #cb2431;
}
.btn-danger {
color: #cb2431;
transition: none;
}
+18 -16
View File
@@ -60,7 +60,7 @@
{"Client acknowledged more stanzas than sent by server","El client ha reconegut més paquets dels que ha enviat el servidor"}.
{"Commands","Comandaments"}.
{"Conference room does not exist","La sala de conferències no existeix"}.
{"Configuration of room ~ts","Configuració de la sala ~ts"}.
{"Configuration of room ~s","Configuració de la sala ~s"}.
{"Configuration","Configuració"}.
{"Connected Resources:","Recursos connectats:"}.
{"Country","Pais"}.
@@ -79,7 +79,8 @@
{"Delete User","Eliminar Usuari"}.
{"Description:","Descripció:"}.
{"Disc only copy","Còpia sols en disc"}.
{"Displayed Groups:","Mostrar grups:"}.
{"'Displayed groups' not added (they do not exist!): ","'Mostrats' no afegits (no existeixen!): "}.
{"Displayed:","Mostrats:"}.
{"Don't tell your password to anybody, not even the administrators of the Jabber server.","No li donis la teva contrasenya a ningú, ni tan sols als administradors del servidor Jabber."}.
{"Dump Backup to Text File at ","Exporta còpia de seguretat a fitxer de text en "}.
{"Dump to Text File","Exportar a fitxer de text"}.
@@ -116,7 +117,7 @@
{"Failed to extract JID from your voice request approval","No s'ha pogut extraure el JID de la teva aprovació de petició de veu"}.
{"Failed to map delegated namespace to external component","Ha fallat mapejar la delegació de l'espai de noms al component extern"}.
{"Failed to parse HTTP response","Ha fallat el processat de la resposta HTTP"}.
{"Failed to process option '~ts'","Ha fallat el processat de la opció '~ts'"}.
{"Failed to process option '~s'","Ha fallat el processat de la opció '~s'"}.
{"Family Name","Cognom"}.
{"February","Febrer"}.
{"File larger than ~w bytes","El fitxer es més gran que ~w bytes"}.
@@ -132,7 +133,7 @@
{"Get User Password","Obtenir Contrasenya d'usuari"}.
{"Get User Statistics","Obtenir Estadístiques d'Usuari"}.
{"Given Name","Nom propi"}.
{"Group ","Grup "}.
{"Group","Grup"}.
{"Groups","Grups"}.
{"has been banned","ha sigut bloquejat"}.
{"has been kicked because of a system shutdown","ha sigut expulsat perquè el sistema va a apagar-se"}.
@@ -169,7 +170,7 @@
{"Invitations are not allowed in this conference","Les invitacions no estan permeses en aquesta sala de conferència"}.
{"IP addresses","Adreça IP"}.
{"is now known as","ara es conegut com"}.
{"It is not allowed to send error messages to the room. The participant (~ts) has sent an error message (~ts) and got kicked from the room","No està permés enviar missatges d'error a la sala. El participant (~ts) ha enviat un missatge d'error (~ts) i ha sigut expulsat de la sala"}.
{"It is not allowed to send error messages to the room. The participant (~s) has sent an error message (~s) and got kicked from the room","No està permés enviar missatges d'error a la sala. El participant (~s) ha enviat un missatge d'error (~s) i ha sigut expulsat de la sala"}.
{"It is not allowed to send private messages of type \"groupchat\"","No està permés enviar missatges del tipus \"groupchat\""}.
{"It is not allowed to send private messages to the conference","No està permès l'enviament de missatges privats a la sala"}.
{"It is not allowed to send private messages","No està permés enviar missatges privats"}.
@@ -181,6 +182,7 @@
{"joins the room","entra a la sala"}.
{"July","Juliol"}.
{"June","Juny"}.
{"Label:","Etiqueta:"}.
{"Last Activity","Última activitat"}.
{"Last login","Últim login"}.
{"Last month","Últim mes"}.
@@ -200,7 +202,7 @@
{"March","Març"}.
{"Maximum Number of Occupants","Número màxim d'ocupants"}.
{"May","Maig"}.
{"Members not added (inexistent vhost): ","Membres no afegits (perque el vhost no existeix): "}.
{"Members not added (inexistent vhost!): ","Membres no afegits (perquè el vhost no existeix): "}.
{"Membership is required to enter this room","Necessites ser membre d'aquesta sala per a poder entrar"}.
{"Members:","Membre:"}.
{"Memorize your password, or write it in a paper placed in a safe place. In Jabber there isn't an automated way to recover your password if you forget it.","Memoritza la teva contrasenya, o escriu-la en un paper guardat a un lloc segur.A Jabber no hi ha una forma automatitzada de recuperar la teva contrasenya si la oblides."}.
@@ -224,7 +226,7 @@
{"New Password:","Nova Contrasenya:"}.
{"Nickname can't be empty","El sobrenom no pot estar buit"}.
{"Nickname Registration at ","Registre del sobrenom en "}.
{"Nickname ~ts does not exist in the room","El sobrenom ~ts no existeix a la sala"}.
{"Nickname ~s does not exist in the room","El sobrenom ~s no existeix a la sala"}.
{"Nickname","Sobrenom"}.
{"No address elements found","No s'han trobat elements d'adreces ('address')"}.
{"No addresses element found","No s'ha trobat l'element d'adreces ('addresses')"}.
@@ -349,6 +351,7 @@
{"Roster","Llista de contactes"}.
{"RPC Call Error","Error de cridada RPC"}.
{"Running Nodes","Nodes funcionant"}.
{"~s invites you to the room ~s","~s et convida a la sala ~s"}.
{"Saturday","Dissabte"}.
{"Script check","Comprovar script"}.
{"Search Results for ","Resultats de la búsqueda "}.
@@ -409,12 +412,12 @@
{"This page allows to create a Jabber account in this Jabber server. Your JID (Jabber IDentifier) will be of the form: username@server. Please read carefully the instructions to fill correctly the fields.","Aquesta pàgina permet crear un compte Jabber en aquest servidor Jabber. El teu JID (Jabber IDentifier; Identificador Jabber) tindrà aquesta forma: usuari@servidor. Si us plau, llegeix amb cura les instruccions per emplenar correctament els camps."}.
{"This page allows to unregister a Jabber account in this Jabber server.","Aquesta pàgina permet anul·lar el registre d'un compte Jabber en aquest servidor Jabber."}.
{"This room is not anonymous","Aquesta sala no és anònima"}.
{"This service can not process the address: ~ts","Este servei no pot processar la direcció: ~ts"}.
{"This service can not process the address: ~s","Este servei no pot processar la direcció: ~s"}.
{"Thursday","Dijous"}.
{"Time delay","Temps de retard"}.
{"Timed out waiting for stream resumption","Massa temps esperant que es resumisca la connexió"}.
{"Time","Data"}.
{"To register, visit ~ts","Per a registrar-te, visita ~ts"}.
{"To register, visit ~s","Per a registrar-te, visita ~s"}.
{"To ~ts","A ~ts"}.
{"Token TTL","Token TTL"}.
{"Too many active bytestreams","N'hi ha massa Bytestreams actius"}.
@@ -422,7 +425,7 @@
{"Too many child elements","N'hi ha massa subelements"}.
{"Too many <item/> elements","N'hi ha massa elements <item/>"}.
{"Too many <list/> elements","N'hi ha massa elements <list/>"}.
{"Too many (~p) failed authentications from this IP address (~ts). The address will be unblocked at ~ts UTC","Massa autenticacions (~p) han fallat des d'aquesta adreça IP (~ts). L'adreça serà desbloquejada en ~ts UTC"}.
{"Too many (~p) failed authentications from this IP address (~s). The address will be unblocked at ~s UTC","Massa autenticacions (~p) han fallat des d'aquesta adreça IP (~s). L'adreça serà desbloquejada en ~s UTC"}.
{"Too many receiver fields were specified","S'han especificat massa camps de receptors"}.
{"Too many unacked stanzas","Massa missatges sense haver reconegut la seva recepció"}.
{"Too many users in this conference","N'hi ha massa usuaris en esta sala de conferència"}.
@@ -433,7 +436,6 @@
{"Transactions Committed:","Transaccions Realitzades:"}.
{"Transactions Logged:","Transaccions registrades:"}.
{"Transactions Restarted:","Transaccions reiniciades:"}.
{"~ts invites you to the room ~ts","~ts et convida a la sala ~ts"}.
{"~ts's Offline Messages Queue","~ts's cua de missatges offline"}.
{"Tuesday","Dimarts"}.
{"Unable to generate a CAPTCHA","No s'ha pogut generar un CAPTCHA"}.
@@ -467,12 +469,11 @@
{"User","Usuari"}.
{"Validate","Validar"}.
{"Value 'get' of 'type' attribute is not allowed","El valor 'get' a l'atribut 'type' no és permès"}.
{"Value of '~ts' should be boolean","El valor de '~ts' deuria ser booleà"}.
{"Value of '~ts' should be datetime string","El valor de '~ts' deuria ser una data"}.
{"Value of '~ts' should be integer","El valor de '~ts' deuria ser un numero enter"}.
{"Value of '~s' should be boolean","El valor de '~s' deuria ser booleà"}.
{"Value of '~s' should be datetime string","El valor de '~s' deuria ser una data"}.
{"Value of '~s' should be integer","El valor de '~s' deuria ser un numero enter"}.
{"Value 'set' of 'type' attribute is not allowed","El valor 'set' a l'atribut 'type' no és permès"}.
{"vCard User Search","vCard recerca d'usuari"}.
{"Virtual Hosting","Hosts virtuals"}.
{"Virtual Hosts","Hosts virtuals"}.
{"Visitors are not allowed to change their nicknames in this room","Els visitants no tenen permés canviar el seus Nicknames en esta sala"}.
{"Visitors are not allowed to send messages to all occupants","Els visitants no poden enviar missatges a tots els ocupants"}.
@@ -481,6 +482,7 @@
{"Wednesday","Dimecres"}.
{"Wrong parameters in the web formulary","Paràmetres incorrectes en el formulari web"}.
{"Wrong xmlns","El xmlns ès incorrecte"}.
{"XMPP Domains","Dominis XMPP"}.
{"You are being removed from the room because of a system shutdown","Has sigut expulsat de la sala perquè el sistema va a apagar-se"}.
{"You are not joined to the channel","No t'has unit al canal"}.
{"You can later change your password using a Jabber client.","Podràs canviar la teva contrasenya més endavant utilitzant un client Jabber."}.
@@ -494,5 +496,5 @@
{"Your contact offline message queue is full. The message has been discarded.","La teua cua de missatges offline és plena. El missatge ha sigut descartat."}.
{"Your Jabber account was successfully created.","El teu compte Jabber ha sigut creat correctament."}.
{"Your Jabber account was successfully deleted.","El teu compte Jabber ha sigut esborrat correctament."}.
{"Your subscription request and/or messages to ~ts have been blocked. To unblock your subscription request, visit ~ts","La teua petició de subscripció i/o missatges a ~ts han sigut bloquejats. Per a desbloquejar-los, visita ~ts"}.
{"Your subscription request and/or messages to ~s have been blocked. To unblock your subscription request, visit ~s","La teua petició de subscripció i/o missatges a ~s han sigut bloquejats. Per a desbloquejar-los, visita ~s"}.
{"You're not allowed to create nodes","No tens permís per a crear nodes"}.
+366 -355
View File
File diff suppressed because it is too large Load Diff
+15 -25
View File
@@ -291,8 +291,7 @@ msgid "Configuration"
msgstr "Konfigurace"
#: mod_muc_room.erl:3489
#, fuzzy
msgid "Configuration of room ~ts"
msgid "Configuration of room ~s"
msgstr "Konfigurace místnosti ~s"
#: ejabberd_web_admin.erl:937
@@ -495,8 +494,7 @@ msgid "Failed to parse HTTP response"
msgstr "Chyba parsování HTTP odpovědi"
#: mod_muc_room.erl:3632
#, fuzzy
msgid "Failed to process option '~ts'"
msgid "Failed to process option '~s'"
msgstr "Chyba při zpracování možnosti '~s'"
#: mod_vcard_mnesia.erl:103 mod_vcard_mnesia.erl:117 mod_vcard_sql.erl:160
@@ -565,8 +563,8 @@ msgid "Given Name"
msgstr "Křestní jméno"
#: mod_shared_roster.erl:879
msgid "Group "
msgstr "Skupina "
msgid "Group"
msgstr "Skupina"
#: mod_roster.erl:956
msgid "Groups"
@@ -694,10 +692,9 @@ msgid "Invitations are not allowed in this conference"
msgstr "Pozvánky nejsou povoleny v této místnosti"
#: mod_muc_room.erl:373 mod_muc_room.erl:519 mod_muc_room.erl:1293
#, fuzzy
msgid ""
"It is not allowed to send error messages to the room. The participant (~ts) "
"has sent an error message (~ts) and got kicked from the room"
"It is not allowed to send error messages to the room. The participant (~s) "
"has sent an error message (~s) and got kicked from the room"
msgstr ""
"Není povoleno posílat chybové zprávy do místnosti. Účastník (~s) odeslal "
"chybovou zprávu (~s) a byl vyhozen z místnosti"
@@ -933,8 +930,7 @@ msgid "Nickname can't be empty"
msgstr ""
#: mod_muc_room.erl:2994
#, fuzzy
msgid "Nickname ~ts does not exist in the room"
msgid "Nickname ~s does not exist in the room"
msgstr "Přezdívka ~s v místnosti neexistuje"
#: mod_muc_room.erl:3396
@@ -1767,8 +1763,7 @@ msgid "To"
msgstr "Pro"
#: mod_register.erl:226
#, fuzzy
msgid "To register, visit ~ts"
msgid "To register, visit ~s"
msgstr "Pokud se chcete zaregistrovat, navštivte ~s"
#: mod_configure.erl:666
@@ -1781,10 +1776,9 @@ msgid "Token TTL"
msgstr "Token TTL"
#: mod_fail2ban.erl:219
#, fuzzy
msgid ""
"Too many (~p) failed authentications from this IP address (~ts). The address "
"will be unblocked at ~ts UTC"
"Too many (~p) failed authentications from this IP address (~s). The address "
"will be unblocked at ~s UTC"
msgstr ""
"Příliš mnoho (~p) chybných pokusů o přihlášení z této IP adresy (~s). Adresa "
"bude zablokována do ~s UTC"
@@ -1996,19 +1990,16 @@ msgid "Value 'set' of 'type' attribute is not allowed"
msgstr "Hodnota 'set' atrubutu 'type' není povolena"
#: pubsub_subscription.erl:237 pubsub_subscription_sql.erl:202
#, fuzzy
msgid "Value of '~ts' should be boolean"
msgid "Value of '~s' should be boolean"
msgstr "Hodnota '~s' by měla být boolean"
#: pubsub_subscription.erl:215 pubsub_subscription_sql.erl:180
#, fuzzy
msgid "Value of '~ts' should be datetime string"
msgid "Value of '~s' should be datetime string"
msgstr "Hodnota '~s' by měla být datetime řetězec"
#: pubsub_subscription.erl:209 pubsub_subscription.erl:227
#: pubsub_subscription_sql.erl:174 pubsub_subscription_sql.erl:192
#, fuzzy
msgid "Value of '~ts' should be integer"
msgid "Value of '~s' should be integer"
msgstr "Hodnota '~s' by měla být celé číslo"
#: ejabberd_web_admin.erl:433
@@ -2109,10 +2100,9 @@ msgid ""
msgstr "Fronta offline zpráv pro váš kontakt je plná. Zpráva byla zahozena."
#: ejabberd_captcha.erl:97
#, fuzzy
msgid ""
"Your subscription request and/or messages to ~ts have been blocked. To "
"unblock your subscription request, visit ~ts"
"Your subscription request and/or messages to ~s have been blocked. To "
"unblock your subscription request, visit ~s"
msgstr "Nesmíte posílat zprávy na ~s. Pro povolení navštivte ~s"
#: mod_disco.erl:438
+15 -25
View File
@@ -300,8 +300,7 @@ msgid "Configuration"
msgstr "Konfiguration"
#: mod_muc_room.erl:3489
#, fuzzy
msgid "Configuration of room ~ts"
msgid "Configuration of room ~s"
msgstr "Konfiguration für Raum ~s"
#: ejabberd_web_admin.erl:937
@@ -507,8 +506,7 @@ msgid "Failed to parse HTTP response"
msgstr "Konnte HTTP-Antwort nicht parsen"
#: mod_muc_room.erl:3632
#, fuzzy
msgid "Failed to process option '~ts'"
msgid "Failed to process option '~s'"
msgstr "Konnte Option '~s' nicht verarbeiten"
#: mod_vcard_mnesia.erl:103 mod_vcard_mnesia.erl:117 mod_vcard_sql.erl:160
@@ -578,8 +576,8 @@ msgid "Given Name"
msgstr "Vorname"
#: mod_shared_roster.erl:879
msgid "Group "
msgstr "Gruppe "
msgid "Group"
msgstr "Gruppe"
#: mod_roster.erl:956
msgid "Groups"
@@ -708,10 +706,9 @@ msgid "Invitations are not allowed in this conference"
msgstr "Einladungen sind in dieser Konferenz nicht erlaubt"
#: mod_muc_room.erl:373 mod_muc_room.erl:519 mod_muc_room.erl:1293
#, fuzzy
msgid ""
"It is not allowed to send error messages to the room. The participant (~ts) "
"has sent an error message (~ts) and got kicked from the room"
"It is not allowed to send error messages to the room. The participant (~s) "
"has sent an error message (~s) and got kicked from the room"
msgstr ""
"Es ist nicht erlaubt Fehlermeldungen an den Raum zu senden. Der Teilnehmer "
"(~s) hat eine Fehlermeldung (~s) gesendet und wurde aus dem Raum gekickt"
@@ -949,8 +946,7 @@ msgid "Nickname can't be empty"
msgstr ""
#: mod_muc_room.erl:2994
#, fuzzy
msgid "Nickname ~ts does not exist in the room"
msgid "Nickname ~s does not exist in the room"
msgstr "Der Benutzername ~s existiert im Raum nicht"
#: mod_muc_room.erl:3396
@@ -1790,8 +1786,7 @@ msgid "To"
msgstr "An"
#: mod_register.erl:226
#, fuzzy
msgid "To register, visit ~ts"
msgid "To register, visit ~s"
msgstr "Um sich anzumelden, besuchen Sie ~s"
#: mod_configure.erl:666
@@ -1804,10 +1799,9 @@ msgid "Token TTL"
msgstr "Token TTL"
#: mod_fail2ban.erl:219
#, fuzzy
msgid ""
"Too many (~p) failed authentications from this IP address (~ts). The address "
"will be unblocked at ~ts UTC"
"Too many (~p) failed authentications from this IP address (~s). The address "
"will be unblocked at ~s UTC"
msgstr ""
"Zu viele (~p) fehlgeschlagene Anmeldeversuche von dieser IP Adresse (~s). "
"Die Adresse wird bis ~s UTC blockiert."
@@ -2019,19 +2013,16 @@ msgid "Value 'set' of 'type' attribute is not allowed"
msgstr "Wert 'set' des 'type'-Attributs ist nicht erlaubt"
#: pubsub_subscription.erl:237 pubsub_subscription_sql.erl:202
#, fuzzy
msgid "Value of '~ts' should be boolean"
msgid "Value of '~s' should be boolean"
msgstr "Wert von '~s' sollte boolesch sein"
#: pubsub_subscription.erl:215 pubsub_subscription_sql.erl:180
#, fuzzy
msgid "Value of '~ts' should be datetime string"
msgid "Value of '~s' should be datetime string"
msgstr "Wert von '~s' sollte datetime-String sein"
#: pubsub_subscription.erl:209 pubsub_subscription.erl:227
#: pubsub_subscription_sql.erl:174 pubsub_subscription_sql.erl:192
#, fuzzy
msgid "Value of '~ts' should be integer"
msgid "Value of '~s' should be integer"
msgstr "Wert von '~s' sollte eine Ganzzahl sein"
#: ejabberd_web_admin.erl:433
@@ -2140,10 +2131,9 @@ msgstr ""
"verworfen."
#: ejabberd_captcha.erl:97
#, fuzzy
msgid ""
"Your subscription request and/or messages to ~ts have been blocked. To "
"unblock your subscription request, visit ~ts"
"Your subscription request and/or messages to ~s have been blocked. To "
"unblock your subscription request, visit ~s"
msgstr ""
"Ihre Nachrichten an ~s werden blockiert. Um dies zu ändern, besuchen Sie ~s"
+20 -29
View File
@@ -294,8 +294,7 @@ msgid "Configuration"
msgstr "Διαμόρφωση"
#: mod_muc_room.erl:3489
#, fuzzy
msgid "Configuration of room ~ts"
msgid "Configuration of room ~s"
msgstr "Διαμόρφωση Αίθουσας σύνεδριασης ~s"
#: ejabberd_web_admin.erl:937
@@ -505,9 +504,8 @@ msgid "Failed to parse HTTP response"
msgstr "Αποτυχία ανάλυσης της απόκρισης HTTP"
#: mod_muc_room.erl:3632
#, fuzzy
msgid "Failed to process option '~ts'"
msgstr "Αποτυχία επεξεργασίας της επιλογής '~ s'"
msgid "Failed to process option '~s'"
msgstr "Αποτυχία επεξεργασίας της επιλογής '~s'"
#: mod_vcard_mnesia.erl:103 mod_vcard_mnesia.erl:117 mod_vcard_sql.erl:160
#: mod_vcard_sql.erl:174 mod_vcard_ldap.erl:330 mod_vcard_ldap.erl:343
@@ -576,8 +574,8 @@ msgid "Given Name"
msgstr "Ονομα"
#: mod_shared_roster.erl:879
msgid "Group "
msgstr "Ομάδα "
msgid "Group"
msgstr "Ομάδα"
#: mod_roster.erl:956
msgid "Groups"
@@ -705,13 +703,12 @@ msgid "Invitations are not allowed in this conference"
msgstr "Οι προσκλήσεις δεν επιτρέπονται σε αυτή τη διάσκεψη"
#: mod_muc_room.erl:373 mod_muc_room.erl:519 mod_muc_room.erl:1293
#, fuzzy
msgid ""
"It is not allowed to send error messages to the room. The participant (~ts) "
"has sent an error message (~ts) and got kicked from the room"
"It is not allowed to send error messages to the room. The participant (~s) "
"has sent an error message (~s) and got kicked from the room"
msgstr ""
"Δεν επιτρέπεται η αποστολή μηνυμάτων σφάλματος στο δωμάτιο. Ο συμμετέχων (~ "
"s) έχει στείλει ένα μήνυμα σφάλματος (~ s) και έχει πέταχτεί έξω από την "
"Δεν επιτρέπεται η αποστολή μηνυμάτων σφάλματος στο δωμάτιο. Ο συμμετέχων (~s"
") έχει στείλει ένα μήνυμα σφάλματος (~s) και έχει πέταχτεί έξω από την "
"αίθουσα"
#: mod_muc_room.erl:564 mod_muc_room.erl:575
@@ -946,8 +943,7 @@ msgid "Nickname can't be empty"
msgstr ""
#: mod_muc_room.erl:2994
#, fuzzy
msgid "Nickname ~ts does not exist in the room"
msgid "Nickname ~s does not exist in the room"
msgstr "Ψευδώνυμο ~s δεν υπάρχει σε αυτή την αίθουσα"
#: mod_muc_room.erl:3396
@@ -1797,9 +1793,8 @@ msgid "To"
msgstr "Πρώς"
#: mod_register.erl:226
#, fuzzy
msgid "To register, visit ~ts"
msgstr "Για να εγγραφείτε, επισκεφθείτε το ~ s"
msgid "To register, visit ~s"
msgstr "Για να εγγραφείτε, επισκεφθείτε το ~s"
#: mod_configure.erl:666
#, fuzzy
@@ -2025,20 +2020,17 @@ msgid "Value 'set' of 'type' attribute is not allowed"
msgstr "Δεν επιτρέπεται η παράμετρος 'set' του 'type'"
#: pubsub_subscription.erl:237 pubsub_subscription_sql.erl:202
#, fuzzy
msgid "Value of '~ts' should be boolean"
msgstr "Η τιμή του '~ s' πρέπει να είναι boolean"
msgid "Value of '~s' should be boolean"
msgstr "Η τιμή του '~s' πρέπει να είναι boolean"
#: pubsub_subscription.erl:215 pubsub_subscription_sql.erl:180
#, fuzzy
msgid "Value of '~ts' should be datetime string"
msgstr "Η τιμή του '~ s' θα πρέπει να είναι χρονοσειρά"
msgid "Value of '~s' should be datetime string"
msgstr "Η τιμή του '~s' θα πρέπει να είναι χρονοσειρά"
#: pubsub_subscription.erl:209 pubsub_subscription.erl:227
#: pubsub_subscription_sql.erl:174 pubsub_subscription_sql.erl:192
#, fuzzy
msgid "Value of '~ts' should be integer"
msgstr "Η τιμή του '~ s' θα πρέπει να είναι ακέραιος"
msgid "Value of '~s' should be integer"
msgstr "Η τιμή του '~s' θα πρέπει να είναι ακέραιος"
#: ejabberd_web_admin.erl:433
#, fuzzy
@@ -2146,10 +2138,9 @@ msgstr ""
"Η μνήμη χωρίς σύνδεση μήνυματών είναι πλήρης. Το μήνυμα έχει απορριφθεί."
#: ejabberd_captcha.erl:97
#, fuzzy
msgid ""
"Your subscription request and/or messages to ~ts have been blocked. To "
"unblock your subscription request, visit ~ts"
"Your subscription request and/or messages to ~s have been blocked. To "
"unblock your subscription request, visit ~s"
msgstr ""
"Τα μηνύματά σας πρως ~s είναι αποκλεισμένα. Για αποδεσμεύση, επισκεφθείτε ~s"
+8 -12
View File
@@ -290,8 +290,7 @@ msgid "Configuration"
msgstr "Agordo"
#: mod_muc_room.erl:3489
#, fuzzy
msgid "Configuration of room ~ts"
msgid "Configuration of room ~s"
msgstr "Agordo de babilejo ~s"
#: ejabberd_web_admin.erl:937
@@ -566,8 +565,8 @@ msgid "Given Name"
msgstr "Meza Nomo"
#: mod_shared_roster.erl:879
msgid "Group "
msgstr "Grupo "
msgid "Group"
msgstr "Grupo"
#: mod_roster.erl:956
msgid "Groups"
@@ -936,8 +935,7 @@ msgid "Nickname can't be empty"
msgstr ""
#: mod_muc_room.erl:2994
#, fuzzy
msgid "Nickname ~ts does not exist in the room"
msgid "Nickname ~s does not exist in the room"
msgstr "Kaŝnomo ~s ne ekzistas en la babilejo"
#: mod_muc_room.erl:3396
@@ -1782,10 +1780,9 @@ msgid "Token TTL"
msgstr ""
#: mod_fail2ban.erl:219
#, fuzzy
msgid ""
"Too many (~p) failed authentications from this IP address (~ts). The address "
"will be unblocked at ~ts UTC"
"Too many (~p) failed authentications from this IP address (~s). The address "
"will be unblocked at ~s UTC"
msgstr ""
"Tro da malsukcesaj aŭtentprovoj (~p) de ĉi tiu IP-adreso (~s). La adreso "
"estos malbarata je ~s UTC."
@@ -2113,10 +2110,9 @@ msgstr ""
"forĵetita"
#: ejabberd_captcha.erl:97
#, fuzzy
msgid ""
"Your subscription request and/or messages to ~ts have been blocked. To "
"unblock your subscription request, visit ~ts"
"Your subscription request and/or messages to ~s have been blocked. To "
"unblock your subscription request, visit ~s"
msgstr "Viaj mesaĝoj al ~s estas blokata. Por malbloki ilin, iru al ~s"
#: mod_disco.erl:438
+18 -16
View File
@@ -60,7 +60,7 @@
{"Client acknowledged more stanzas than sent by server","El cliente ha reconocido más paquetes de los que el servidor ha enviado"}.
{"Commands","Comandos"}.
{"Conference room does not exist","La sala de conferencias no existe"}.
{"Configuration of room ~ts","Configuración para la sala ~ts"}.
{"Configuration of room ~s","Configuración para la sala ~s"}.
{"Configuration","Configuración"}.
{"Connected Resources:","Recursos conectados:"}.
{"Country","País"}.
@@ -79,7 +79,8 @@
{"Delete User","Borrar usuario"}.
{"Description:","Descripción:"}.
{"Disc only copy","Copia en disco solamente"}.
{"Displayed Groups:","Mostrar grupos:"}.
{"'Displayed groups' not added (they do not exist!): ","'Mostrados' que no han sido añadidos (¡no existen!): "}.
{"Displayed:","Mostrados:"}.
{"Don't tell your password to anybody, not even the administrators of the Jabber server.","No le digas tu contraseña a nadie, ni siquiera a los administradores del servidor Jabber."}.
{"Dump Backup to Text File at ","Exporta copia de seguridad a fichero de texto en "}.
{"Dump to Text File","Exportar a fichero de texto"}.
@@ -116,7 +117,7 @@
{"Failed to extract JID from your voice request approval","Fallo al extraer el Jabber ID de tu aprobación de petición de voz"}.
{"Failed to map delegated namespace to external component","Falló el mapeo de espacio de nombres delegado al componente externo"}.
{"Failed to parse HTTP response","Falló la comprensión de la respuesta HTTP"}.
{"Failed to process option '~ts'","Falló el procesado de la opción '~ts'"}.
{"Failed to process option '~s'","Falló el procesado de la opción '~s'"}.
{"Family Name","Apellido"}.
{"February","febrero"}.
{"File larger than ~w bytes","El fichero es más grande que ~w bytes"}.
@@ -132,7 +133,7 @@
{"Get User Password","Ver contraseña de usuario"}.
{"Get User Statistics","Ver estadísticas de usuario"}.
{"Given Name","Nombre"}.
{"Group ","Grupo "}.
{"Group","Grupo"}.
{"Groups","Grupos"}.
{"has been banned","ha sido bloqueado"}.
{"has been kicked because of a system shutdown","ha sido expulsado porque el sistema se va a detener"}.
@@ -169,7 +170,7 @@
{"Invitations are not allowed in this conference","Las invitaciones no están permitidas en esta sala"}.
{"IP addresses","Direcciones IP"}.
{"is now known as","se cambia el nombre a"}.
{"It is not allowed to send error messages to the room. The participant (~ts) has sent an error message (~ts) and got kicked from the room","No está permitido enviar mensajes de error a la sala. Este participante (~ts) ha enviado un mensaje de error (~ts) y fue expulsado de la sala"}.
{"It is not allowed to send error messages to the room. The participant (~s) has sent an error message (~s) and got kicked from the room","No está permitido enviar mensajes de error a la sala. Este participante (~s) ha enviado un mensaje de error (~s) y fue expulsado de la sala"}.
{"It is not allowed to send private messages of type \"groupchat\"","No está permitido enviar mensajes privados del tipo \"groupchat\""}.
{"It is not allowed to send private messages to the conference","Impedir el envio de mensajes privados a la sala"}.
{"It is not allowed to send private messages","No está permitido enviar mensajes privados"}.
@@ -181,6 +182,7 @@
{"joins the room","entra en la sala"}.
{"July","julio"}.
{"June","junio"}.
{"Label:","Etiqueta:"}.
{"Last Activity","Última actividad"}.
{"Last login","Última conexión"}.
{"Last month","Último mes"}.
@@ -200,7 +202,7 @@
{"March","marzo"}.
{"Maximum Number of Occupants","Número máximo de ocupantes"}.
{"May","mayo"}.
{"Members not added (inexistent vhost): ","Miembros no añadidos (el vhost no existe): "}.
{"Members not added (inexistent vhost!): ","Miembros no añadidos (el vhost no existe): "}.
{"Membership is required to enter this room","Necesitas ser miembro de esta sala para poder entrar"}.
{"Members:","Miembros:"}.
{"Memorize your password, or write it in a paper placed in a safe place. In Jabber there isn't an automated way to recover your password if you forget it.","Memoriza tu contraseña, o apúntala en un papel en un lugar seguro. En Jabber no hay un método automatizado para recuperar la contraseña si la olvidas."}.
@@ -224,7 +226,7 @@
{"New Password:","Nueva contraseña:"}.
{"Nickname can't be empty","El apodo no puede estar vacío"}.
{"Nickname Registration at ","Registro del apodo en "}.
{"Nickname ~ts does not exist in the room","El apodo ~ts no existe en la sala"}.
{"Nickname ~s does not exist in the room","El apodo ~s no existe en la sala"}.
{"Nickname","Apodo"}.
{"No address elements found","No se encontraron elementos de dirección ('address')"}.
{"No addresses element found","No se encontró elemento de direcciones ('addresses')"}.
@@ -349,6 +351,7 @@
{"Roster","Lista de contactos"}.
{"RPC Call Error","Error en la llamada RPC"}.
{"Running Nodes","Nodos funcionando"}.
{"~s invites you to the room ~s","~s te invita a la sala ~s"}.
{"Saturday","sábado"}.
{"Script check","Comprobación de script"}.
{"Search Results for ","Buscar resultados por "}.
@@ -409,12 +412,12 @@
{"This page allows to create a Jabber account in this Jabber server. Your JID (Jabber IDentifier) will be of the form: username@server. Please read carefully the instructions to fill correctly the fields.","Esta página te permite crear una cuenta Jabber este servidor Jabber. Tu JID (Jabber IDentificador) será de la forma: nombredeusuario@servidor. Por favor lee detenidamente las instrucciones para rellenar correctamente los campos."}.
{"This page allows to unregister a Jabber account in this Jabber server.","Esta página te permite borrar tu cuenta Jabber en este servidor Jabber."}.
{"This room is not anonymous","Sala no anónima"}.
{"This service can not process the address: ~ts","Este servicio no puede procesar la dirección: ~ts"}.
{"This service can not process the address: ~s","Este servicio no puede procesar la dirección: ~s"}.
{"Thursday","jueves"}.
{"Time delay","Retraso temporal"}.
{"Timed out waiting for stream resumption","Ha pasado demasiado tiempo esperando que la conexión se restablezca"}.
{"Time","Fecha"}.
{"To register, visit ~ts","Para registrarte, visita ~ts"}.
{"To register, visit ~s","Para registrarte, visita ~s"}.
{"To ~ts","A ~ts"}.
{"Token TTL","Token TTL"}.
{"Too many active bytestreams","Demasiados bytestreams activos"}.
@@ -422,7 +425,7 @@
{"Too many child elements","Demasiados subelementos"}.
{"Too many <item/> elements","Demasiados elementos <item/>"}.
{"Too many <list/> elements","Demasiados elementos <list/>"}.
{"Too many (~p) failed authentications from this IP address (~ts). The address will be unblocked at ~ts UTC","Demasiadas (~p) autenticaciones fallidas de esta dirección IP (~ts). La dirección será desbloqueada en ~ts UTC"}.
{"Too many (~p) failed authentications from this IP address (~s). The address will be unblocked at ~s UTC","Demasiadas (~p) autenticaciones fallidas de esta dirección IP (~s). La dirección será desbloqueada en ~s UTC"}.
{"Too many receiver fields were specified","Se han especificado demasiados campos de destinatario"}.
{"Too many unacked stanzas","Demasiados mensajes sin haber reconocido recibirlos"}.
{"Too many users in this conference","Demasiados usuarios en esta sala"}.
@@ -433,7 +436,6 @@
{"Transactions Committed:","Transacciones finalizadas:"}.
{"Transactions Logged:","Transacciones registradas:"}.
{"Transactions Restarted:","Transacciones reiniciadas:"}.
{"~ts invites you to the room ~ts","~ts te invita a la sala ~ts"}.
{"~ts's Offline Messages Queue","Cola de mensajes diferidos de ~ts"}.
{"Tuesday","martes"}.
{"Unable to generate a CAPTCHA","No se pudo generar un CAPTCHA"}.
@@ -467,12 +469,11 @@
{"User","Usuario"}.
{"Validate","Validar"}.
{"Value 'get' of 'type' attribute is not allowed","El valor 'get' del atributo 'type' no está permitido"}.
{"Value of '~ts' should be boolean","El valor de '~ts' debería ser booleano"}.
{"Value of '~ts' should be datetime string","El valor de '~ts' debería ser una fecha"}.
{"Value of '~ts' should be integer","El valor de '~ts' debería ser un entero"}.
{"Value of '~s' should be boolean","El valor de '~s' debería ser booleano"}.
{"Value of '~s' should be datetime string","El valor de '~s' debería ser una fecha"}.
{"Value of '~s' should be integer","El valor de '~s' debería ser un entero"}.
{"Value 'set' of 'type' attribute is not allowed","El valor 'set' del atributo 'type' no está permitido"}.
{"vCard User Search","Buscar vCard de usuario"}.
{"Virtual Hosting","Dominios Virtuales"}.
{"Virtual Hosts","Dominios Virtuales"}.
{"Visitors are not allowed to change their nicknames in this room","Los visitantes no tienen permitido cambiar sus apodos en esta sala"}.
{"Visitors are not allowed to send messages to all occupants","Los visitantes no pueden enviar mensajes a todos los ocupantes"}.
@@ -481,6 +482,7 @@
{"Wednesday","miércoles"}.
{"Wrong parameters in the web formulary","Parámetros incorrectos en el formulario web"}.
{"Wrong xmlns","xmlns incorrecto"}.
{"XMPP Domains","Dominios XMPP"}.
{"You are being removed from the room because of a system shutdown","Estás siendo expulsado de la sala porque el sistema se va a detener"}.
{"You are not joined to the channel","No has entrado en el canal"}.
{"You can later change your password using a Jabber client.","Puedes cambiar tu contraseña después, usando un cliente Jabber."}.
@@ -494,5 +496,5 @@
{"Your contact offline message queue is full. The message has been discarded.","Tu cola de mensajes diferidos de contactos está llena. El mensaje se ha descartado."}.
{"Your Jabber account was successfully created.","Tu cuenta Jabber se ha creado correctamente."}.
{"Your Jabber account was successfully deleted.","Tu cuenta Jabber se ha borrado correctamente."}.
{"Your subscription request and/or messages to ~ts have been blocked. To unblock your subscription request, visit ~ts","Tu petición de suscripción y/o mensajes a ~ts ha sido bloqueado. Para desbloquear tu petición de suscripción visita ~ts"}.
{"Your subscription request and/or messages to ~s have been blocked. To unblock your subscription request, visit ~s","Tu petición de suscripción y/o mensajes a ~s ha sido bloqueado. Para desbloquear tu petición de suscripción visita ~s"}.
{"You're not allowed to create nodes","No tienes permitido crear nodos"}.
+422 -412
View File
File diff suppressed because it is too large Load Diff
+15 -25
View File
@@ -293,8 +293,7 @@ msgid "Configuration"
msgstr "Configuration"
#: mod_muc_room.erl:3489
#, fuzzy
msgid "Configuration of room ~ts"
msgid "Configuration of room ~s"
msgstr "Configuration pour le salon ~s"
#: ejabberd_web_admin.erl:937
@@ -501,8 +500,7 @@ msgid "Failed to parse HTTP response"
msgstr "Echec de lecture de la réponse HTTP"
#: mod_muc_room.erl:3632
#, fuzzy
msgid "Failed to process option '~ts'"
msgid "Failed to process option '~s'"
msgstr "Echec de traitement de l'option '~s'"
#: mod_vcard_mnesia.erl:103 mod_vcard_mnesia.erl:117 mod_vcard_sql.erl:160
@@ -571,8 +569,8 @@ msgid "Given Name"
msgstr "Nom"
#: mod_shared_roster.erl:879
msgid "Group "
msgstr "Groupe "
msgid "Group"
msgstr "Groupe"
#: mod_roster.erl:956
msgid "Groups"
@@ -701,10 +699,9 @@ msgid "Invitations are not allowed in this conference"
msgstr "Les invitations ne sont pas autorisées dans ce salon"
#: mod_muc_room.erl:373 mod_muc_room.erl:519 mod_muc_room.erl:1293
#, fuzzy
msgid ""
"It is not allowed to send error messages to the room. The participant (~ts) "
"has sent an error message (~ts) and got kicked from the room"
"It is not allowed to send error messages to the room. The participant (~s) "
"has sent an error message (~s) and got kicked from the room"
msgstr ""
"L'envoyer de messages d'erreur au salon n'est pas autorisé. Le participant "
"(~s) à envoyé un message d'erreur (~s) et à été expulsé du salon"
@@ -942,8 +939,7 @@ msgid "Nickname can't be empty"
msgstr ""
#: mod_muc_room.erl:2994
#, fuzzy
msgid "Nickname ~ts does not exist in the room"
msgid "Nickname ~s does not exist in the room"
msgstr "Le pseudo ~s n'existe pas dans ce salon"
#: mod_muc_room.erl:3396
@@ -1784,8 +1780,7 @@ msgid "To"
msgstr "A"
#: mod_register.erl:226
#, fuzzy
msgid "To register, visit ~ts"
msgid "To register, visit ~s"
msgstr "Pour vous enregistrer, visitez ~s"
#: mod_configure.erl:666
@@ -1798,10 +1793,9 @@ msgid "Token TTL"
msgstr "Jeton TTL"
#: mod_fail2ban.erl:219
#, fuzzy
msgid ""
"Too many (~p) failed authentications from this IP address (~ts). The address "
"will be unblocked at ~ts UTC"
"Too many (~p) failed authentications from this IP address (~s). The address "
"will be unblocked at ~s UTC"
msgstr ""
"Trop (~p) d'authentification ont échoué pour cette adresse IP (~s). "
"L'adresse sera débloquée à ~s UTC"
@@ -2016,19 +2010,16 @@ msgid "Value 'set' of 'type' attribute is not allowed"
msgstr "La valeur de l'attribut 'type' ne peut être 'set'"
#: pubsub_subscription.erl:237 pubsub_subscription_sql.erl:202
#, fuzzy
msgid "Value of '~ts' should be boolean"
msgid "Value of '~s' should be boolean"
msgstr "La valeur de '~s' ne peut être booléen"
#: pubsub_subscription.erl:215 pubsub_subscription_sql.erl:180
#, fuzzy
msgid "Value of '~ts' should be datetime string"
msgid "Value of '~s' should be datetime string"
msgstr "La valeur de '~s' doit être une chaine datetime"
#: pubsub_subscription.erl:209 pubsub_subscription.erl:227
#: pubsub_subscription_sql.erl:174 pubsub_subscription_sql.erl:192
#, fuzzy
msgid "Value of '~ts' should be integer"
msgid "Value of '~s' should be integer"
msgstr "La valeur de '~s' doit être un entier"
#: ejabberd_web_admin.erl:433
@@ -2139,10 +2130,9 @@ msgstr ""
"été détruit."
#: ejabberd_captcha.erl:97
#, fuzzy
msgid ""
"Your subscription request and/or messages to ~ts have been blocked. To "
"unblock your subscription request, visit ~ts"
"Your subscription request and/or messages to ~s have been blocked. To "
"unblock your subscription request, visit ~s"
msgstr ""
"Vos messages pour ~s sont bloqués. Pour les débloquer, veuillez visiter ~s"
+15 -25
View File
@@ -291,8 +291,7 @@ msgid "Configuration"
msgstr "Configuración"
#: mod_muc_room.erl:3489
#, fuzzy
msgid "Configuration of room ~ts"
msgid "Configuration of room ~s"
msgstr "Configuración para a sala ~s"
#: ejabberd_web_admin.erl:937
@@ -498,8 +497,7 @@ msgid "Failed to parse HTTP response"
msgstr "Non se puido analizar a resposta HTTP"
#: mod_muc_room.erl:3632
#, fuzzy
msgid "Failed to process option '~ts'"
msgid "Failed to process option '~s'"
msgstr "Fallo ao procesar a opción '~s'"
#: mod_vcard_mnesia.erl:103 mod_vcard_mnesia.erl:117 mod_vcard_sql.erl:160
@@ -568,8 +566,8 @@ msgid "Given Name"
msgstr "Nome"
#: mod_shared_roster.erl:879
msgid "Group "
msgstr "Grupo "
msgid "Group"
msgstr "Grupo"
#: mod_roster.erl:956
msgid "Groups"
@@ -697,10 +695,9 @@ msgid "Invitations are not allowed in this conference"
msgstr "As invitacións non están permitidas nesta sala"
#: mod_muc_room.erl:373 mod_muc_room.erl:519 mod_muc_room.erl:1293
#, fuzzy
msgid ""
"It is not allowed to send error messages to the room. The participant (~ts) "
"has sent an error message (~ts) and got kicked from the room"
"It is not allowed to send error messages to the room. The participant (~s) "
"has sent an error message (~s) and got kicked from the room"
msgstr ""
"Non está permitido enviar mensaxes de erro á sala. Este participante (~s) "
"enviou unha mensaxe de erro (~s) e foi expulsado da sala"
@@ -937,8 +934,7 @@ msgid "Nickname can't be empty"
msgstr ""
#: mod_muc_room.erl:2994
#, fuzzy
msgid "Nickname ~ts does not exist in the room"
msgid "Nickname ~s does not exist in the room"
msgstr "O alcume ~s non existe na sala"
#: mod_muc_room.erl:3396
@@ -1776,8 +1772,7 @@ msgid "To"
msgstr "Para"
#: mod_register.erl:226
#, fuzzy
msgid "To register, visit ~ts"
msgid "To register, visit ~s"
msgstr "Para rexistrarse, visita ~s"
#: mod_configure.erl:666
@@ -1790,10 +1785,9 @@ msgid "Token TTL"
msgstr "Token TTL"
#: mod_fail2ban.erl:219
#, fuzzy
msgid ""
"Too many (~p) failed authentications from this IP address (~ts). The address "
"will be unblocked at ~ts UTC"
"Too many (~p) failed authentications from this IP address (~s). The address "
"will be unblocked at ~s UTC"
msgstr ""
"Demasiados (~p) fallou autenticaciones desde esta dirección IP (~s). A "
"dirección será desbloqueada as ~s UTC"
@@ -2005,19 +1999,16 @@ msgid "Value 'set' of 'type' attribute is not allowed"
msgstr "O valor \"set\" do atributo 'type' non está permitido"
#: pubsub_subscription.erl:237 pubsub_subscription_sql.erl:202
#, fuzzy
msgid "Value of '~ts' should be boolean"
msgid "Value of '~s' should be boolean"
msgstr "O valor de '~s' debería ser booleano"
#: pubsub_subscription.erl:215 pubsub_subscription_sql.erl:180
#, fuzzy
msgid "Value of '~ts' should be datetime string"
msgid "Value of '~s' should be datetime string"
msgstr "O valor de '~s' debería ser unha data"
#: pubsub_subscription.erl:209 pubsub_subscription.erl:227
#: pubsub_subscription_sql.erl:174 pubsub_subscription_sql.erl:192
#, fuzzy
msgid "Value of '~ts' should be integer"
msgid "Value of '~s' should be integer"
msgstr "O valor de '~s' debería ser un enteiro"
#: ejabberd_web_admin.erl:433
@@ -2122,10 +2113,9 @@ msgstr ""
"descartouse."
#: ejabberd_captcha.erl:97
#, fuzzy
msgid ""
"Your subscription request and/or messages to ~ts have been blocked. To "
"unblock your subscription request, visit ~ts"
"Your subscription request and/or messages to ~s have been blocked. To "
"unblock your subscription request, visit ~s"
msgstr ""
"As súas mensaxes a ~s encóntranse bloqueadas. Para desbloquear, visite ~s"
+14 -23
View File
@@ -295,8 +295,7 @@ msgstr "תצורה"
# תצורה של חדר
#: mod_muc_room.erl:3489
#, fuzzy
msgid "Configuration of room ~ts"
msgid "Configuration of room ~s"
msgstr "תצורת חדר ~s"
#: ejabberd_web_admin.erl:937
@@ -500,8 +499,7 @@ msgid "Failed to parse HTTP response"
msgstr "נכשל לפענח תגובת HTTP"
#: mod_muc_room.erl:3632
#, fuzzy
msgid "Failed to process option '~ts'"
msgid "Failed to process option '~s'"
msgstr "נכשל לעבד אפשרות '~s'"
#: mod_vcard_mnesia.erl:103 mod_vcard_mnesia.erl:117 mod_vcard_sql.erl:160
@@ -572,8 +570,8 @@ msgid "Given Name"
msgstr "שם פרטי"
#: mod_shared_roster.erl:879
msgid "Group "
msgstr "קבוצה "
msgid "Group"
msgstr "קבוצה"
#: mod_roster.erl:956
msgid "Groups"
@@ -702,10 +700,9 @@ msgid "Invitations are not allowed in this conference"
msgstr "הזמנות אינן מותרות בועידה זו"
#: mod_muc_room.erl:373 mod_muc_room.erl:519 mod_muc_room.erl:1293
#, fuzzy
msgid ""
"It is not allowed to send error messages to the room. The participant (~ts) "
"has sent an error message (~ts) and got kicked from the room"
"It is not allowed to send error messages to the room. The participant (~s) "
"has sent an error message (~s) and got kicked from the room"
msgstr ""
"אין זה מותר לשלוח הודעות שגיאה לחדר. משתתף זה (~s) שלח הודעת שגיאה (~s) "
"ונבעט מתוך החדר"
@@ -1784,8 +1781,7 @@ msgid "To"
msgstr "לכבוד"
#: mod_register.erl:226
#, fuzzy
msgid "To register, visit ~ts"
msgid "To register, visit ~s"
msgstr "כדי להירשם, בקרו ~s"
#: mod_configure.erl:666
@@ -1798,10 +1794,9 @@ msgid "Token TTL"
msgstr "סימן TTL"
#: mod_fail2ban.erl:219
#, fuzzy
msgid ""
"Too many (~p) failed authentications from this IP address (~ts). The address "
"will be unblocked at ~ts UTC"
"Too many (~p) failed authentications from this IP address (~s). The address "
"will be unblocked at ~s UTC"
msgstr ""
"יותר מדי (~p) אימותים כושלים מתוך כתובת IP זו (~s). הכתובת תורשה לקבל גישה "
"בשעה ~s UTC"
@@ -2015,19 +2010,16 @@ msgid "Value 'set' of 'type' attribute is not allowed"
msgstr ""
#: pubsub_subscription.erl:237 pubsub_subscription_sql.erl:202
#, fuzzy
msgid "Value of '~ts' should be boolean"
msgid "Value of '~s' should be boolean"
msgstr "ערך של '~s' צריך להיות boolean"
#: pubsub_subscription.erl:215 pubsub_subscription_sql.erl:180
#, fuzzy
msgid "Value of '~ts' should be datetime string"
msgid "Value of '~s' should be datetime string"
msgstr "ערך של '~s' צריך להיות מחרוזת datetime"
#: pubsub_subscription.erl:209 pubsub_subscription.erl:227
#: pubsub_subscription_sql.erl:174 pubsub_subscription_sql.erl:192
#, fuzzy
msgid "Value of '~ts' should be integer"
msgid "Value of '~s' should be integer"
msgstr "ערך של '~s' צריך להיות integer"
# וירטואליים
@@ -2132,10 +2124,9 @@ msgid ""
msgstr "תור הודעות קשר לא מקוונות הינו מלא. ההודעה סולקה."
#: ejabberd_captcha.erl:97
#, fuzzy
msgid ""
"Your subscription request and/or messages to ~ts have been blocked. To "
"unblock your subscription request, visit ~ts"
"Your subscription request and/or messages to ~s have been blocked. To "
"unblock your subscription request, visit ~s"
msgstr "ההודעות שלך לערוץ ~s הינן חסומות. כדי לבטל את חסימתן, בקר בכתובת ~s"
#: mod_disco.erl:438
+24 -25
View File
@@ -295,8 +295,8 @@ msgid "Configuration"
msgstr "Beállítás"
#: mod_muc_room.erl:3489
msgid "Configuration of room ~ts"
msgstr "A(z) ~ts szoba beállítása"
msgid "Configuration of room ~s"
msgstr "A(z) ~s szoba beállítása"
#: ejabberd_web_admin.erl:937
msgid "Connected Resources:"
@@ -567,8 +567,8 @@ msgid "Given Name"
msgstr "Keresztnév"
#: mod_shared_roster.erl:879
msgid "Group "
msgstr "Csoport "
msgid "Group"
msgstr "Csoport"
#: mod_roster.erl:956
msgid "Groups"
@@ -694,11 +694,11 @@ msgstr "Meghívások nem engedélyezettek ebben a konferenciában"
#: mod_muc_room.erl:373 mod_muc_room.erl:519 mod_muc_room.erl:1293
msgid ""
"It is not allowed to send error messages to the room. The participant (~ts) "
"has sent an error message (~ts) and got kicked from the room"
"It is not allowed to send error messages to the room. The participant (~s) "
"has sent an error message (~s) and got kicked from the room"
msgstr ""
"Nem engedélyezett hibaüzeneteket küldeni a szobába. A résztvevő (~ts) "
"hibaüzenetet (~ts) küldött, és ki lett rúgva a szobából"
"Nem engedélyezett hibaüzeneteket küldeni a szobába. A résztvevő (~s) "
"hibaüzenetet (~s) küldött, és ki lett rúgva a szobából"
#: mod_muc_room.erl:564 mod_muc_room.erl:575
msgid "It is not allowed to send private messages"
@@ -1734,8 +1734,8 @@ msgid "This room is not anonymous"
msgstr "Ez a szoba nem névtelen"
#: mod_multicast.erl:498
msgid "This service can not process the address: ~ts"
msgstr "Ez a szolgáltatás nem tudja feldolgozni a címet: ~ts"
msgid "This service can not process the address: ~s"
msgstr "Ez a szolgáltatás nem tudja feldolgozni a címet: ~s"
#: mod_muc_log.erl:470
msgid "Thursday"
@@ -1758,8 +1758,8 @@ msgid "To"
msgstr "Címzett"
#: mod_register.erl:226
msgid "To register, visit ~ts"
msgstr "Regisztráláshoz látogassa meg ezt az oldalt: ~ts"
msgid "To register, visit ~s"
msgstr "Regisztráláshoz látogassa meg ezt az oldalt: ~s"
#: mod_configure.erl:666
msgid "To ~ts"
@@ -1769,10 +1769,9 @@ msgstr "Címzett: ~ts"
msgid "Token TTL"
msgstr "Token élettartama"
#: mod_fail2ban.erl:219
msgid ""
"Too many (~p) failed authentications from this IP address (~ts). The address "
"will be unblocked at ~ts UTC"
"Too many (~p) failed authentications from this IP address (~s). The address "
"will be unblocked at ~s UTC"
msgstr ""
"Túl sok (~p) sikertelen hitelesítés erről az IP-címről (~ts) A cím ~ts-kor "
"lesz feloldva UTC szerint"
@@ -1981,17 +1980,17 @@ msgid "Value 'set' of 'type' attribute is not allowed"
msgstr "A „type” attribútum „set” értéke nem engedélyezett"
#: pubsub_subscription.erl:237 pubsub_subscription_sql.erl:202
msgid "Value of '~ts' should be boolean"
msgstr "A(z) „~ts” értéke csak logikai lehet"
msgid "Value of '~s' should be boolean"
msgstr "A(z) „~s” értéke csak logikai lehet"
#: pubsub_subscription.erl:215 pubsub_subscription_sql.erl:180
msgid "Value of '~ts' should be datetime string"
msgstr "A(z) „~ts” értéke csak dátum és idő karakterlánc lehet"
msgid "Value of '~s' should be datetime string"
msgstr "A(z) „~s” értéke csak dátum és idő karakterlánc lehet"
#: pubsub_subscription.erl:209 pubsub_subscription.erl:227
#: pubsub_subscription_sql.erl:174 pubsub_subscription_sql.erl:192
msgid "Value of '~ts' should be integer"
msgstr "A(z) „~ts” értéke csak egész szám lehet"
msgid "Value of '~s' should be integer"
msgstr "A(z) „~s” értéke csak egész szám lehet"
#: ejabberd_web_admin.erl:433
msgid "Virtual Hosting"
@@ -2097,12 +2096,12 @@ msgstr ""
#: ejabberd_captcha.erl:97
msgid ""
"Your subscription request and/or messages to ~ts have been blocked. To "
"unblock your subscription request, visit ~ts"
"Your subscription request and/or messages to ~s have been blocked. To "
"unblock your subscription request, visit ~s"
msgstr ""
"A feliratkozási kérelme és/vagy ~ts számára küldött üzenetei blokkolva "
"A feliratkozási kérelme és/vagy ~s számára küldött üzenetei blokkolva "
"lettek. A feliratkozási kérelmének feloldásához látogassa meg ezt az oldalt: "
"~ts"
"~s"
#: mod_disco.erl:438
msgid "ejabberd"
+6 -8
View File
@@ -291,8 +291,7 @@ msgid "Configuration"
msgstr "Pengaturan"
#: mod_muc_room.erl:3489
#, fuzzy
msgid "Configuration of room ~ts"
msgid "Configuration of room ~s"
msgstr "Pengaturan ruangan ~s"
#: ejabberd_web_admin.erl:937
@@ -568,10 +567,11 @@ msgid "Given Name"
msgstr "Nama Tengah"
#: mod_shared_roster.erl:879
msgid "Group "
msgid "Group"
msgstr "Grup"
#: mod_roster.erl:956
#, fuzzy
msgid "Groups"
msgstr "Grup"
@@ -940,8 +940,7 @@ msgid "Nickname can't be empty"
msgstr ""
#: mod_muc_room.erl:2994
#, fuzzy
msgid "Nickname ~ts does not exist in the room"
msgid "Nickname ~s does not exist in the room"
msgstr "Nama Julukan ~s tidak berada di dalam ruangan"
#: mod_muc_room.erl:3396
@@ -2126,10 +2125,9 @@ msgstr ""
"Kontak offline Anda pada antrian pesan sudah penuh. Pesan telah dibuang."
#: ejabberd_captcha.erl:97
#, fuzzy
msgid ""
"Your subscription request and/or messages to ~ts have been blocked. To "
"unblock your subscription request, visit ~ts"
"Your subscription request and/or messages to ~s have been blocked. To "
"unblock your subscription request, visit ~s"
msgstr ""
"Pesan Anda untuk ~s sedang diblokir. Untuk membuka blokir tersebut, kunjungi "
"~s"
+6 -9
View File
@@ -298,8 +298,7 @@ msgid "Configuration"
msgstr "Configurazione"
#: mod_muc_room.erl:3489
#, fuzzy
msgid "Configuration of room ~ts"
msgid "Configuration of room ~s"
msgstr "Configurazione per la stanza ~s"
#: ejabberd_web_admin.erl:937
@@ -577,8 +576,8 @@ msgid "Given Name"
msgstr "Altro nome"
#: mod_shared_roster.erl:879
msgid "Group "
msgstr "Gruppo "
msgid "Group"
msgstr "Gruppo"
#: mod_roster.erl:956
msgid "Groups"
@@ -947,8 +946,7 @@ msgid "Nickname can't be empty"
msgstr ""
#: mod_muc_room.erl:2994
#, fuzzy
msgid "Nickname ~ts does not exist in the room"
msgid "Nickname ~s does not exist in the room"
msgstr "Il nickname ~s non esiste nella stanza"
#: mod_muc_room.erl:3396
@@ -2135,10 +2133,9 @@ msgstr ""
"scartato"
#: ejabberd_captcha.erl:97
#, fuzzy
msgid ""
"Your subscription request and/or messages to ~ts have been blocked. To "
"unblock your subscription request, visit ~ts"
"Your subscription request and/or messages to ~s have been blocked. To "
"unblock your subscription request, visit ~s"
msgstr "I messaggi verso ~s sono bloccati. Per sbloccarli, visitare ~s"
#: mod_disco.erl:438
+11 -14
View File
@@ -288,8 +288,7 @@ msgid "Configuration"
msgstr "設定"
#: mod_muc_room.erl:3489
#, fuzzy
msgid "Configuration of room ~ts"
msgid "Configuration of room ~s"
msgstr "チャットルーム ~s の設定"
#: ejabberd_web_admin.erl:937
@@ -565,10 +564,12 @@ msgid "Given Name"
msgstr "ミドルネーム"
#: mod_shared_roster.erl:879
msgid "Group "
#, fuzzy
msgid "Group"
msgstr "グループ"
#: mod_roster.erl:956
#, fuzzy
msgid "Groups"
msgstr "グループ"
@@ -697,10 +698,9 @@ msgid "Invitations are not allowed in this conference"
msgstr "この会議では、発言権の要求はできません"
#: mod_muc_room.erl:373 mod_muc_room.erl:519 mod_muc_room.erl:1293
#, fuzzy
msgid ""
"It is not allowed to send error messages to the room. The participant (~ts) "
"has sent an error message (~ts) and got kicked from the room"
"It is not allowed to send error messages to the room. The participant (~s) "
"has sent an error message (~s) and got kicked from the room"
msgstr ""
"このルームにエラーメッセージを送ることは許可されていません。参加者(~s)はエ"
"ラーメッセージを(~s)を送信してルームからキックされました。"
@@ -939,8 +939,7 @@ msgid "Nickname can't be empty"
msgstr ""
#: mod_muc_room.erl:2994
#, fuzzy
msgid "Nickname ~ts does not exist in the room"
msgid "Nickname ~s does not exist in the room"
msgstr "ニックネーム ~s はこのチャットルームにいません"
#: mod_muc_room.erl:3396
@@ -1783,10 +1782,9 @@ msgid "Token TTL"
msgstr ""
#: mod_fail2ban.erl:219
#, fuzzy
msgid ""
"Too many (~p) failed authentications from this IP address (~ts). The address "
"will be unblocked at ~ts UTC"
"Too many (~p) failed authentications from this IP address (~s). The address "
"will be unblocked at ~s UTC"
msgstr ""
"~p回の認証に失敗しました。このIPアドレス(~s)は~s UTCまでブロックされます。"
@@ -2109,10 +2107,9 @@ msgstr ""
"相手先のオフラインメッセージキューが一杯です。このメッセージは破棄されます。"
#: ejabberd_captcha.erl:97
#, fuzzy
msgid ""
"Your subscription request and/or messages to ~ts have been blocked. To "
"unblock your subscription request, visit ~ts"
"Your subscription request and/or messages to ~s have been blocked. To "
"unblock your subscription request, visit ~s"
msgstr ""
"~s 宛のメッセージはブロックされています。解除するにはこちらを見てください ~s"
+8 -12
View File
@@ -292,8 +292,7 @@ msgid "Configuration"
msgstr "Instellingen"
#: mod_muc_room.erl:3489
#, fuzzy
msgid "Configuration of room ~ts"
msgid "Configuration of room ~s"
msgstr "Instellingen van chatruimte ~s"
#: ejabberd_web_admin.erl:937
@@ -571,8 +570,8 @@ msgid "Given Name"
msgstr "Tussennaam"
#: mod_shared_roster.erl:879
msgid "Group "
msgstr "Groep "
msgid "Group"
msgstr "Groep"
#: mod_roster.erl:956
msgid "Groups"
@@ -946,8 +945,7 @@ msgid "Nickname can't be empty"
msgstr ""
#: mod_muc_room.erl:2994
#, fuzzy
msgid "Nickname ~ts does not exist in the room"
msgid "Nickname ~s does not exist in the room"
msgstr "De bijnaam ~s bestaat niet in deze chatruimte"
#: mod_muc_room.erl:3396
@@ -1807,10 +1805,9 @@ msgid "Token TTL"
msgstr ""
#: mod_fail2ban.erl:219
#, fuzzy
msgid ""
"Too many (~p) failed authentications from this IP address (~ts). The address "
"will be unblocked at ~ts UTC"
"Too many (~p) failed authentications from this IP address (~s). The address "
"will be unblocked at ~s UTC"
msgstr ""
"Te veel (~p) mislukte authenticatie-pogingen van dit IP-adres (~s). Dit "
"adres zal worden gedeblokkeerd om ~s UTC"
@@ -2138,10 +2135,9 @@ msgstr ""
"opgeslagen."
#: ejabberd_captcha.erl:97
#, fuzzy
msgid ""
"Your subscription request and/or messages to ~ts have been blocked. To "
"unblock your subscription request, visit ~ts"
"Your subscription request and/or messages to ~s have been blocked. To "
"unblock your subscription request, visit ~s"
msgstr ""
"Uw berichten aan ~s worden geblokkeerd. Om ze te deblokkeren, ga naar ~s"
+6 -9
View File
@@ -290,8 +290,7 @@ msgid "Configuration"
msgstr "Konfigurasjon"
#: mod_muc_room.erl:3489
#, fuzzy
msgid "Configuration of room ~ts"
msgid "Configuration of room ~s"
msgstr "Konfigurasjon for rom ~s"
#: ejabberd_web_admin.erl:937
@@ -566,8 +565,8 @@ msgid "Given Name"
msgstr "Mellomnavn"
#: mod_shared_roster.erl:879
msgid "Group "
msgstr "Gruppe "
msgid "Group"
msgstr "Gruppe"
#: mod_roster.erl:956
msgid "Groups"
@@ -936,8 +935,7 @@ msgid "Nickname can't be empty"
msgstr ""
#: mod_muc_room.erl:2994
#, fuzzy
msgid "Nickname ~ts does not exist in the room"
msgid "Nickname ~s does not exist in the room"
msgstr "Kallenavn ~s eksisterer ikke i dette rommet"
#: mod_muc_room.erl:3396
@@ -2108,10 +2106,9 @@ msgid ""
msgstr "Kontaktens frakoblede meldingskø er full. Meldingen har blitt kassert."
#: ejabberd_captcha.erl:97
#, fuzzy
msgid ""
"Your subscription request and/or messages to ~ts have been blocked. To "
"unblock your subscription request, visit ~ts"
"Your subscription request and/or messages to ~s have been blocked. To "
"unblock your subscription request, visit ~s"
msgstr "Dine meldinger til ~s blir blokkert. For å åpne igjen, besøk ~s"
#: mod_disco.erl:438
+14 -23
View File
@@ -294,8 +294,7 @@ msgid "Configuration"
msgstr "Konfiguracja"
#: mod_muc_room.erl:3489
#, fuzzy
msgid "Configuration of room ~ts"
msgid "Configuration of room ~s"
msgstr "Konfiguracja pokoju ~s"
#: ejabberd_web_admin.erl:937
@@ -500,8 +499,7 @@ msgid "Failed to parse HTTP response"
msgstr "Nie udało się zanalizować odpowiedzi HTTP"
#: mod_muc_room.erl:3632
#, fuzzy
msgid "Failed to process option '~ts'"
msgid "Failed to process option '~s'"
msgstr "Nie udało się przetworzyć opcji '~s'"
#: mod_vcard_mnesia.erl:103 mod_vcard_mnesia.erl:117 mod_vcard_sql.erl:160
@@ -570,8 +568,8 @@ msgid "Given Name"
msgstr "Imię"
#: mod_shared_roster.erl:879
msgid "Group "
msgstr "Grupa "
msgid "Group"
msgstr "Grupa"
#: mod_roster.erl:956
msgid "Groups"
@@ -699,10 +697,9 @@ msgid "Invitations are not allowed in this conference"
msgstr "Zaproszenia są wyłączone w tym pokoju"
#: mod_muc_room.erl:373 mod_muc_room.erl:519 mod_muc_room.erl:1293
#, fuzzy
msgid ""
"It is not allowed to send error messages to the room. The participant (~ts) "
"has sent an error message (~ts) and got kicked from the room"
"It is not allowed to send error messages to the room. The participant (~s) "
"has sent an error message (~s) and got kicked from the room"
msgstr ""
"Użytkownik nie może wysyłać wiadomości o błędach do pokoju. Użytkownik (~s) "
"wysłał błąd (~s) i został wyrzucony z pokoju"
@@ -1776,8 +1773,7 @@ msgid "To"
msgstr "Do"
#: mod_register.erl:226
#, fuzzy
msgid "To register, visit ~ts"
msgid "To register, visit ~s"
msgstr "Żeby się zarejestrować odwiedź ~s"
#: mod_configure.erl:666
@@ -1790,10 +1786,9 @@ msgid "Token TTL"
msgstr "Limit czasu tokenu"
#: mod_fail2ban.erl:219
#, fuzzy
msgid ""
"Too many (~p) failed authentications from this IP address (~ts). The address "
"will be unblocked at ~ts UTC"
"Too many (~p) failed authentications from this IP address (~s). The address "
"will be unblocked at ~s UTC"
msgstr ""
"Zbyt wiele (~p) nieudanych prób logowanie z tego adresu IP (~s). Ten adres "
"zostanie odblokowany o ~s UTC"
@@ -2005,19 +2000,16 @@ msgid "Value 'set' of 'type' attribute is not allowed"
msgstr "Wartość 'set' dla atrybutu 'type' jest niedozwolona"
#: pubsub_subscription.erl:237 pubsub_subscription_sql.erl:202
#, fuzzy
msgid "Value of '~ts' should be boolean"
msgid "Value of '~s' should be boolean"
msgstr "Wartość '~s' powinna być typu logicznego"
#: pubsub_subscription.erl:215 pubsub_subscription_sql.erl:180
#, fuzzy
msgid "Value of '~ts' should be datetime string"
msgid "Value of '~s' should be datetime string"
msgstr "Wartość '~s' powinna być typu daty"
#: pubsub_subscription.erl:209 pubsub_subscription.erl:227
#: pubsub_subscription_sql.erl:174 pubsub_subscription_sql.erl:192
#, fuzzy
msgid "Value of '~ts' should be integer"
msgid "Value of '~s' should be integer"
msgstr "Wartość '~s' powinna być liczbą"
#: ejabberd_web_admin.erl:433
@@ -2118,10 +2110,9 @@ msgstr ""
"Kolejka wiadomości offline adresata jest pełna. Wiadomość została odrzucona."
#: ejabberd_captcha.erl:97
#, fuzzy
msgid ""
"Your subscription request and/or messages to ~ts have been blocked. To "
"unblock your subscription request, visit ~ts"
"Your subscription request and/or messages to ~s have been blocked. To "
"unblock your subscription request, visit ~s"
msgstr "Twoje wiadomości do ~s są blokowane. Aby je odblokować, odwiedź ~s"
#: mod_disco.erl:438
+15 -25
View File
@@ -291,8 +291,7 @@ msgid "Configuration"
msgstr "Configuração"
#: mod_muc_room.erl:3489
#, fuzzy
msgid "Configuration of room ~ts"
msgid "Configuration of room ~s"
msgstr "Configuração para ~s"
#: ejabberd_web_admin.erl:937
@@ -499,8 +498,7 @@ msgid "Failed to parse HTTP response"
msgstr "Falha ao analisar resposta HTTP"
#: mod_muc_room.erl:3632
#, fuzzy
msgid "Failed to process option '~ts'"
msgid "Failed to process option '~s'"
msgstr "Falha ao processar opção '~s'"
#: mod_vcard_mnesia.erl:103 mod_vcard_mnesia.erl:117 mod_vcard_sql.erl:160
@@ -570,8 +568,8 @@ msgid "Given Name"
msgstr "Nome do meio"
#: mod_shared_roster.erl:879
msgid "Group "
msgstr "Grupo "
msgid "Group"
msgstr "Grupo"
#: mod_roster.erl:956
msgid "Groups"
@@ -701,10 +699,9 @@ msgid "Invitations are not allowed in this conference"
msgstr "Convites estão desabilitados nesta sala de conferência"
#: mod_muc_room.erl:373 mod_muc_room.erl:519 mod_muc_room.erl:1293
#, fuzzy
msgid ""
"It is not allowed to send error messages to the room. The participant (~ts) "
"has sent an error message (~ts) and got kicked from the room"
"It is not allowed to send error messages to the room. The participant (~s) "
"has sent an error message (~s) and got kicked from the room"
msgstr ""
"Não é permitido o envio de mensagens de erro a esta sala. O membro (~s) "
"enviou uma mensagem de erro (~s) e foi desconectado (\"kicked\")."
@@ -942,8 +939,7 @@ msgid "Nickname can't be empty"
msgstr ""
#: mod_muc_room.erl:2994
#, fuzzy
msgid "Nickname ~ts does not exist in the room"
msgid "Nickname ~s does not exist in the room"
msgstr "O apelido ~s não existe na sala"
#: mod_muc_room.erl:3396
@@ -1784,8 +1780,7 @@ msgid "To"
msgstr "Para"
#: mod_register.erl:226
#, fuzzy
msgid "To register, visit ~ts"
msgid "To register, visit ~s"
msgstr "Para registrar, visite ~s"
#: mod_configure.erl:666
@@ -1798,10 +1793,9 @@ msgid "Token TTL"
msgstr "Token TTL"
#: mod_fail2ban.erl:219
#, fuzzy
msgid ""
"Too many (~p) failed authentications from this IP address (~ts). The address "
"will be unblocked at ~ts UTC"
"Too many (~p) failed authentications from this IP address (~s). The address "
"will be unblocked at ~s UTC"
msgstr ""
"Número excessivo (~p) de tentativas falhas de autenticação (~s). O endereço "
"será desbloqueado às ~s UTC"
@@ -2016,19 +2010,16 @@ msgid "Value 'set' of 'type' attribute is not allowed"
msgstr "Valor 'set' não permitido para atributo 'type'"
#: pubsub_subscription.erl:237 pubsub_subscription_sql.erl:202
#, fuzzy
msgid "Value of '~ts' should be boolean"
msgid "Value of '~s' should be boolean"
msgstr "Value de '~s' deveria ser um booleano"
#: pubsub_subscription.erl:215 pubsub_subscription_sql.erl:180
#, fuzzy
msgid "Value of '~ts' should be datetime string"
msgid "Value of '~s' should be datetime string"
msgstr "Valor de '~s' deveria ser data e hora"
#: pubsub_subscription.erl:209 pubsub_subscription.erl:227
#: pubsub_subscription_sql.erl:174 pubsub_subscription_sql.erl:192
#, fuzzy
msgid "Value of '~ts' should be integer"
msgid "Value of '~s' should be integer"
msgstr "Valor de '~s' deveria ser um inteiro"
#: ejabberd_web_admin.erl:433
@@ -2132,10 +2123,9 @@ msgid ""
msgstr "Sua fila de mensagens offline esta cheia. Sua mensagem foi descartada"
#: ejabberd_captcha.erl:97
#, fuzzy
msgid ""
"Your subscription request and/or messages to ~ts have been blocked. To "
"unblock your subscription request, visit ~ts"
"Your subscription request and/or messages to ~s have been blocked. To "
"unblock your subscription request, visit ~s"
msgstr ""
"Suas mensagens para ~s estão bloqueadas. Para desbloqueá-las, visite: ~s"
+3 -5
View File
@@ -300,7 +300,7 @@ msgstr "Configuração"
#: mod_muc_room.erl:3489
#, fuzzy
msgid "Configuration of room ~ts"
msgid "Configuration of room ~s"
msgstr "Configuração para "
#: ejabberd_web_admin.erl:937
@@ -585,9 +585,8 @@ msgid "Given Name"
msgstr "Segundo nome"
#: mod_shared_roster.erl:879
#, fuzzy
msgid "Group "
msgstr "Grupos"
msgstr ""
#: mod_roster.erl:956
msgid "Groups"
@@ -969,8 +968,7 @@ msgid "Nickname can't be empty"
msgstr ""
#: mod_muc_room.erl:2994
#, fuzzy
msgid "Nickname ~ts does not exist in the room"
msgid "Nickname ~s does not exist in the room"
msgstr "A alcunha ~s não existe na sala"
#: mod_muc_room.erl:3396
+16 -27
View File
@@ -289,8 +289,7 @@ msgid "Configuration"
msgstr "Конфигурация"
#: mod_muc_room.erl:3489
#, fuzzy
msgid "Configuration of room ~ts"
msgid "Configuration of room ~s"
msgstr "Конфигурация комнаты ~s"
#: ejabberd_web_admin.erl:937
@@ -491,8 +490,7 @@ msgid "Failed to parse HTTP response"
msgstr "Ошибка разбора HTTP ответа"
#: mod_muc_room.erl:3632
#, fuzzy
msgid "Failed to process option '~ts'"
msgid "Failed to process option '~s'"
msgstr "Ошибка обработки опции '~s'"
#: mod_vcard_mnesia.erl:103 mod_vcard_mnesia.erl:117 mod_vcard_sql.erl:160
@@ -559,8 +557,8 @@ msgid "Given Name"
msgstr "Имя"
#: mod_shared_roster.erl:879
msgid "Group "
msgstr "Группа "
msgid "Group"
msgstr "Группа"
#: mod_roster.erl:956
msgid "Groups"
@@ -685,10 +683,9 @@ msgid "Invitations are not allowed in this conference"
msgstr "Рассылка приглашений отключена в этой конференции"
#: mod_muc_room.erl:373 mod_muc_room.erl:519 mod_muc_room.erl:1293
#, fuzzy
msgid ""
"It is not allowed to send error messages to the room. The participant (~ts) "
"has sent an error message (~ts) and got kicked from the room"
"It is not allowed to send error messages to the room. The participant (~s) "
"has sent an error message (~s) and got kicked from the room"
msgstr ""
"Запрещено посылать сообщения об ошибках в эту комнату. Участник (~s) послал "
"сообщение об ошибке (~s) и был выкинут из комнаты"
@@ -924,8 +921,7 @@ msgid "Nickname can't be empty"
msgstr "Псевдоним не может быть пустым значением"
#: mod_muc_room.erl:2994
#, fuzzy
msgid "Nickname ~ts does not exist in the room"
msgid "Nickname ~s does not exist in the room"
msgstr "Псевдоним ~s в комнате отсутствует"
#: mod_muc_room.erl:3396
@@ -1726,8 +1722,7 @@ msgid "This room is not anonymous"
msgstr "Эта комната не анонимная"
#: mod_multicast.erl:498
#, fuzzy
msgid "This service can not process the address: ~ts"
msgid "This service can not process the address: ~s"
msgstr "Сервер не может обработать адрес: ~s"
#: mod_muc_log.erl:470
@@ -1751,8 +1746,7 @@ msgid "To"
msgstr "Кому"
#: mod_register.erl:226
#, fuzzy
msgid "To register, visit ~ts"
msgid "To register, visit ~s"
msgstr "Для регистрации посетите ~s"
#: mod_configure.erl:666
@@ -1765,10 +1759,9 @@ msgid "Token TTL"
msgstr "Токен TTL"
#: mod_fail2ban.erl:219
#, fuzzy
msgid ""
"Too many (~p) failed authentications from this IP address (~ts). The address "
"will be unblocked at ~ts UTC"
"Too many (~p) failed authentications from this IP address (~s). The address "
"will be unblocked at ~s UTC"
msgstr ""
"Слишком много (~p) неудачных попыток аутентификации с этого IP-адреса (~s). "
"Адрес будет разблокирован в ~s UTC"
@@ -1977,19 +1970,16 @@ msgid "Value 'set' of 'type' attribute is not allowed"
msgstr "Значение 'set' атрибута 'type' недопустимо"
#: pubsub_subscription.erl:237 pubsub_subscription_sql.erl:202
#, fuzzy
msgid "Value of '~ts' should be boolean"
msgid "Value of '~s' should be boolean"
msgstr "Значение '~s' должно быть булевым"
#: pubsub_subscription.erl:215 pubsub_subscription_sql.erl:180
#, fuzzy
msgid "Value of '~ts' should be datetime string"
msgid "Value of '~s' should be datetime string"
msgstr "Значение '~s' должно быть датой"
#: pubsub_subscription.erl:209 pubsub_subscription.erl:227
#: pubsub_subscription_sql.erl:174 pubsub_subscription_sql.erl:192
#, fuzzy
msgid "Value of '~ts' should be integer"
msgid "Value of '~s' should be integer"
msgstr "Значение '~s' должно быть целочисленным"
#: ejabberd_web_admin.erl:433
@@ -2089,10 +2079,9 @@ msgstr ""
"было сохранено."
#: ejabberd_captcha.erl:97
#, fuzzy
msgid ""
"Your subscription request and/or messages to ~ts have been blocked. To "
"unblock your subscription request, visit ~ts"
"Your subscription request and/or messages to ~s have been blocked. To "
"unblock your subscription request, visit ~s"
msgstr ""
"Ваши запросы на добавление в контакт-лист, а также сообщения к ~s "
"блокируются. Для снятия блокировки перейдите по ссылке ~s"
+6 -9
View File
@@ -291,8 +291,7 @@ msgid "Configuration"
msgstr "Konfigurácia"
#: mod_muc_room.erl:3489
#, fuzzy
msgid "Configuration of room ~ts"
msgid "Configuration of room ~s"
msgstr "Konfigurácia miestnosti ~s"
#: ejabberd_web_admin.erl:937
@@ -567,8 +566,8 @@ msgid "Given Name"
msgstr "Prostredné meno: "
#: mod_shared_roster.erl:879
msgid "Group "
msgstr "Skupina "
msgid "Group"
msgstr "Skupina"
#: mod_roster.erl:956
msgid "Groups"
@@ -936,8 +935,7 @@ msgid "Nickname can't be empty"
msgstr ""
#: mod_muc_room.erl:2994
#, fuzzy
msgid "Nickname ~ts does not exist in the room"
msgid "Nickname ~s does not exist in the room"
msgstr "Prezývka ~s v miestnosti neexistuje"
#: mod_muc_room.erl:3396
@@ -2113,10 +2111,9 @@ msgid ""
msgstr "Fronta offline správ tohoto kontaktu je plná. Správa bola zahodená."
#: ejabberd_captcha.erl:97
#, fuzzy
msgid ""
"Your subscription request and/or messages to ~ts have been blocked. To "
"unblock your subscription request, visit ~ts"
"Your subscription request and/or messages to ~s have been blocked. To "
"unblock your subscription request, visit ~s"
msgstr "Správa určená pre ~s bola zablokovaná. Oblokovať ju môžete na ~s"
#: mod_disco.erl:438
+6 -9
View File
@@ -295,8 +295,7 @@ msgid "Configuration"
msgstr "Konfiguration"
#: mod_muc_room.erl:3489
#, fuzzy
msgid "Configuration of room ~ts"
msgid "Configuration of room ~s"
msgstr "Konfiguration för ~s"
#: ejabberd_web_admin.erl:937
@@ -570,8 +569,8 @@ msgid "Given Name"
msgstr "Mellannamn"
#: mod_shared_roster.erl:879
msgid "Group "
msgstr "Grupp "
msgid "Group"
msgstr "Grupp"
#: mod_roster.erl:956
msgid "Groups"
@@ -942,8 +941,7 @@ msgid "Nickname can't be empty"
msgstr ""
#: mod_muc_room.erl:2994
#, fuzzy
msgid "Nickname ~ts does not exist in the room"
msgid "Nickname ~s does not exist in the room"
msgstr "Smeknamnet ~s existerar inte i det här rummet"
#: mod_muc_room.erl:3396
@@ -2121,10 +2119,9 @@ msgid ""
msgstr "Din kontaktkö for offlinekontakter ar full"
#: ejabberd_captcha.erl:97
#, fuzzy
msgid ""
"Your subscription request and/or messages to ~ts have been blocked. To "
"unblock your subscription request, visit ~ts"
"Your subscription request and/or messages to ~s have been blocked. To "
"unblock your subscription request, visit ~s"
msgstr ""
"Dina meddelanden till ~s är blockerade. För att avblockera dem, gå till ~s"
+2 -2
View File
@@ -569,8 +569,8 @@ msgid "Given Name"
msgstr "ชื่อกลาง"
#: mod_shared_roster.erl:879
msgid "Group "
msgstr "กลุ่"
msgid "Group"
msgstr "กลุ่"
#: mod_roster.erl:956
msgid "Groups"
+5 -8
View File
@@ -294,8 +294,7 @@ msgid "Configuration"
msgstr "Ayarlar"
#: mod_muc_room.erl:3489
#, fuzzy
msgid "Configuration of room ~ts"
msgid "Configuration of room ~s"
msgstr "~s odasının ayarları"
#: ejabberd_web_admin.erl:937
@@ -573,7 +572,7 @@ msgstr "Ortanca İsim"
#: mod_shared_roster.erl:879
msgid "Group "
msgstr "Group "
msgstr ""
#: mod_roster.erl:956
msgid "Groups"
@@ -943,8 +942,7 @@ msgid "Nickname can't be empty"
msgstr ""
#: mod_muc_room.erl:2994
#, fuzzy
msgid "Nickname ~ts does not exist in the room"
msgid "Nickname ~s does not exist in the room"
msgstr "~s takma ismi odada yok"
#: mod_muc_room.erl:3396
@@ -2128,10 +2126,9 @@ msgid ""
msgstr "Çevirim-dışı mesaj kuyruğunuz dolu. Mesajını dikkate alınmadı."
#: ejabberd_captcha.erl:97
#, fuzzy
msgid ""
"Your subscription request and/or messages to ~ts have been blocked. To "
"unblock your subscription request, visit ~ts"
"Your subscription request and/or messages to ~s have been blocked. To "
"unblock your subscription request, visit ~s"
msgstr ""
"~s kullanıcısına mesajlarınız engelleniyor. Durumu düzeltmek için ~s "
"adresini ziyaret ediniz."
+10 -15
View File
@@ -295,8 +295,7 @@ msgid "Configuration"
msgstr "Конфігурація"
#: mod_muc_room.erl:3489
#, fuzzy
msgid "Configuration of room ~ts"
msgid "Configuration of room ~s"
msgstr "Конфігурація кімнати ~s"
#: ejabberd_web_admin.erl:937
@@ -568,8 +567,8 @@ msgid "Given Name"
msgstr "По-батькові"
#: mod_shared_roster.erl:879
msgid "Group "
msgstr "Група "
msgid "Group"
msgstr "Група"
#: mod_roster.erl:956
msgid "Groups"
@@ -699,10 +698,9 @@ msgid "Invitations are not allowed in this conference"
msgstr "Голосові запити відключені в цій конференції"
#: mod_muc_room.erl:373 mod_muc_room.erl:519 mod_muc_room.erl:1293
#, fuzzy
msgid ""
"It is not allowed to send error messages to the room. The participant (~ts) "
"has sent an error message (~ts) and got kicked from the room"
"It is not allowed to send error messages to the room. The participant (~s) "
"has sent an error message (~s) and got kicked from the room"
msgstr ""
"Не дозволяється відправляти помилкові повідомлення в кімнату. Учасник (~s) "
"відправив помилкове повідомлення (~s), та був виганий з кімнати"
@@ -940,8 +938,7 @@ msgid "Nickname can't be empty"
msgstr ""
#: mod_muc_room.erl:2994
#, fuzzy
msgid "Nickname ~ts does not exist in the room"
msgid "Nickname ~s does not exist in the room"
msgstr "Псевдонім ~s в кімнаті відсутній"
#: mod_muc_room.erl:3396
@@ -1794,10 +1791,9 @@ msgid "Token TTL"
msgstr ""
#: mod_fail2ban.erl:219
#, fuzzy
msgid ""
"Too many (~p) failed authentications from this IP address (~ts). The address "
"will be unblocked at ~ts UTC"
"Too many (~p) failed authentications from this IP address (~s). The address "
"will be unblocked at ~s UTC"
msgstr ""
"Забагато (~p) помилок авторизації з цієї IP адреси (~s). Адресу буде "
"розблоковано о ~s UTC"
@@ -2126,10 +2122,9 @@ msgstr ""
"збережено."
#: ejabberd_captcha.erl:97
#, fuzzy
msgid ""
"Your subscription request and/or messages to ~ts have been blocked. To "
"unblock your subscription request, visit ~ts"
"Your subscription request and/or messages to ~s have been blocked. To "
"unblock your subscription request, visit ~s"
msgstr "Ваші повідомлення до ~s блокуються. Для розблокування відвідайте ~s"
#: mod_disco.erl:438
+5 -7
View File
@@ -571,8 +571,8 @@ msgid "Given Name"
msgstr "Họ Đệm"
#: mod_shared_roster.erl:879
msgid "Group "
msgstr "Nhóm "
msgid "Group"
msgstr "Nhóm"
#: mod_roster.erl:956
msgid "Groups"
@@ -946,8 +946,7 @@ msgid "Nickname can't be empty"
msgstr ""
#: mod_muc_room.erl:2994
#, fuzzy
msgid "Nickname ~ts does not exist in the room"
msgid "Nickname ~s does not exist in the room"
msgstr "Bí danh ~s không tồn tại trong phòng này"
#: mod_muc_room.erl:3396
@@ -2140,10 +2139,9 @@ msgid ""
msgstr ""
"Danh sách chờ thư liên lạc ngoại tuyến của bạn đã đầy. Thư này đã bị loại bỏ."
#: ejabberd_captcha.erl:97
msgid ""
"Your subscription request and/or messages to ~ts have been blocked. To "
"unblock your subscription request, visit ~ts"
"Your subscription request and/or messages to ~s have been blocked. To "
"unblock your subscription request, visit ~s"
msgstr ""
#: mod_disco.erl:438
+10 -15
View File
@@ -293,8 +293,7 @@ msgid "Configuration"
msgstr "Apontiaedjes"
#: mod_muc_room.erl:3489
#, fuzzy
msgid "Configuration of room ~ts"
msgid "Configuration of room ~s"
msgstr "Apontiaedje del såle ~s"
#: ejabberd_web_admin.erl:937
@@ -571,8 +570,8 @@ msgid "Given Name"
msgstr "No do mitan"
#: mod_shared_roster.erl:879
msgid "Group "
msgstr "Groupe "
msgid "Group"
msgstr "Groupe"
#: mod_roster.erl:956
msgid "Groups"
@@ -702,10 +701,9 @@ msgid "Invitations are not allowed in this conference"
msgstr "Les dmandes di vwès sont dismetowes e cisse conferince ci"
#: mod_muc_room.erl:373 mod_muc_room.erl:519 mod_muc_room.erl:1293
#, fuzzy
msgid ""
"It is not allowed to send error messages to the room. The participant (~ts) "
"has sent an error message (~ts) and got kicked from the room"
"It is not allowed to send error messages to the room. The participant (~s) "
"has sent an error message (~s) and got kicked from the room"
msgstr ""
"On n' pout nén evoyî des messaedjes d' aroke sol såle. Li pårticipan (~s) a-"
"st evoyî on messaedje d' aroke (~s) ey a stî tapé foû."
@@ -943,8 +941,7 @@ msgid "Nickname can't be empty"
msgstr ""
#: mod_muc_room.erl:2994
#, fuzzy
msgid "Nickname ~ts does not exist in the room"
msgid "Nickname ~s does not exist in the room"
msgstr "Li metou no ~s n' egzistêye nén dins l' såle"
#: mod_muc_room.erl:3396
@@ -1798,10 +1795,9 @@ msgid "Token TTL"
msgstr ""
#: mod_fail2ban.erl:219
#, fuzzy
msgid ""
"Too many (~p) failed authentications from this IP address (~ts). The address "
"will be unblocked at ~ts UTC"
"Too many (~p) failed authentications from this IP address (~s). The address "
"will be unblocked at ~s UTC"
msgstr ""
"I gn a-st avou pår trop (~p) d' otintifiaedjes k' ont fwait berwete vinant "
"di ciste adresse IP la (~s). L' adresse serè disblokêye a ~s UTC"
@@ -2129,10 +2125,9 @@ msgstr ""
"messaedje a stî tapé å diale."
#: ejabberd_captcha.erl:97
#, fuzzy
msgid ""
"Your subscription request and/or messages to ~ts have been blocked. To "
"unblock your subscription request, visit ~ts"
"Your subscription request and/or messages to ~s have been blocked. To "
"unblock your subscription request, visit ~s"
msgstr "Vos messaedjes po ~s sont blokés. Po les disbloker, alez vey ~s"
#: mod_disco.erl:438
+13 -22
View File
@@ -491,8 +491,7 @@ msgid "Failed to parse HTTP response"
msgstr "HTTP响应解析失败"
#: mod_muc_room.erl:3632
#, fuzzy
msgid "Failed to process option '~ts'"
msgid "Failed to process option '~s'"
msgstr "选项'~s'处理失败"
#: mod_vcard_mnesia.erl:103 mod_vcard_mnesia.erl:117 mod_vcard_sql.erl:160
@@ -561,7 +560,7 @@ msgid "Given Name"
msgstr "中间名"
#: mod_shared_roster.erl:879
msgid "Group "
msgid "Group"
msgstr "组"
#: mod_roster.erl:956
@@ -690,10 +689,9 @@ msgid "Invitations are not allowed in this conference"
msgstr "此会议不允许邀请"
#: mod_muc_room.erl:373 mod_muc_room.erl:519 mod_muc_room.erl:1293
#, fuzzy
msgid ""
"It is not allowed to send error messages to the room. The participant (~ts) "
"has sent an error message (~ts) and got kicked from the room"
"It is not allowed to send error messages to the room. The participant (~s) "
"has sent an error message (~s) and got kicked from the room"
msgstr ""
"不允许将错误消息发送到该房间. 参与者(~s)已发送过一条消息(~s)并已被踢出房间"
@@ -928,8 +926,7 @@ msgid "Nickname can't be empty"
msgstr ""
#: mod_muc_room.erl:2994
#, fuzzy
msgid "Nickname ~ts does not exist in the room"
msgid "Nickname ~s does not exist in the room"
msgstr "昵称~s不在该房间"
#: mod_muc_room.erl:3396
@@ -1754,8 +1751,7 @@ msgid "To"
msgstr "到"
#: mod_register.erl:226
#, fuzzy
msgid "To register, visit ~ts"
msgid "To register, visit ~s"
msgstr "要注册,请访问 ~s"
#: mod_configure.erl:666
@@ -1768,10 +1764,9 @@ msgid "Token TTL"
msgstr "TTL令牌"
#: mod_fail2ban.erl:219
#, fuzzy
msgid ""
"Too many (~p) failed authentications from this IP address (~ts). The address "
"will be unblocked at ~ts UTC"
"Too many (~p) failed authentications from this IP address (~s). The address "
"will be unblocked at ~s UTC"
msgstr "来自IP地址(~p)的(~s)失败认证太多. 该地址将在UTC时间~s被禁用."
#: mod_muc_room.erl:2768 mod_muc_room.erl:3402
@@ -1981,19 +1976,16 @@ msgid "Value 'set' of 'type' attribute is not allowed"
msgstr "不允许 'type' 属性的 'set' 值"
#: pubsub_subscription.erl:237 pubsub_subscription_sql.erl:202
#, fuzzy
msgid "Value of '~ts' should be boolean"
msgid "Value of '~s' should be boolean"
msgstr "'~s' 的值应为布尔型"
#: pubsub_subscription.erl:215 pubsub_subscription_sql.erl:180
#, fuzzy
msgid "Value of '~ts' should be datetime string"
msgid "Value of '~s' should be datetime string"
msgstr "'~s' 的值应为日期时间字符串"
#: pubsub_subscription.erl:209 pubsub_subscription.erl:227
#: pubsub_subscription_sql.erl:174 pubsub_subscription_sql.erl:192
#, fuzzy
msgid "Value of '~ts' should be integer"
msgid "Value of '~s' should be integer"
msgstr "'~s' 的值应为整数"
#: ejabberd_web_admin.erl:433
@@ -2093,10 +2085,9 @@ msgid ""
msgstr "您的联系人离线消息队列已满. 消息已被丢弃"
#: ejabberd_captcha.erl:97
#, fuzzy
msgid ""
"Your subscription request and/or messages to ~ts have been blocked. To "
"unblock your subscription request, visit ~ts"
"Your subscription request and/or messages to ~s have been blocked. To "
"unblock your subscription request, visit ~s"
msgstr "您发送给~s的消息已被阻止. 要解除阻止, 请访问 ~s"
#: mod_disco.erl:438
+92 -86
View File
@@ -18,67 +18,72 @@
%%%
%%%----------------------------------------------------------------------
{deps, [{lager, ".*", {git, "https://github.com/erlang-lager/lager", "3.6.10"}},
{p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.18"}}},
{cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.22"}}},
{fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.1.4"}}},
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.19"}}},
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.39"}}},
{idna, ".*", {git, "https://github.com/benoitc/erlang-idna", {tag, "6.0.0"}}},
{xmpp, ".*", {git, "https://github.com/processone/xmpp", {tag, "1.4.5"}}},
{fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.24"}}},
{yconf, ".*", {git, "https://github.com/processone/yconf", {tag, "1.0.4"}}},
{jiffy, ".*", {git, "https://github.com/davisp/jiffy", {tag, "1.0.1"}}},
{p1_oauth2, ".*", {git, "https://github.com/processone/p1_oauth2", {tag, "0.6.6"}}},
{pkix, ".*", {git, "https://github.com/processone/pkix", {tag, "1.0.5"}}},
{deps, [{base64url, ".*", {git, "https://github.com/dvv/base64url.git", {tag, "1.0.1"}}},
{cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.26"}}},
{eimp, ".*", {git, "https://github.com/processone/eimp", {tag, "1.0.18"}}},
{if_var_true, elixir,
{elixir, ".*", {git, "https://github.com/elixir-lang/elixir", {tag, "v1.4.4"}}}},
{if_var_true, pam,
{epam, ".*", {git, "https://github.com/processone/epam", {tag, "1.0.10"}}}},
{if_var_true, redis,
{eredis, ".*", {git, "https://github.com/wooga/eredis", {tag, "v1.0.8"}}}},
{if_var_true, sip,
{esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.39"}}}},
{if_var_true, zlib,
{ezlib, ".*", {git, "https://github.com/processone/ezlib", {tag, "1.0.9"}}}},
{fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.1.10"}}},
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.45"}}},
{fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.29"}}},
{idna, ".*", {git, "https://github.com/benoitc/erlang-idna", {tag, "6.0.0"}}},
{jiffy, ".*", {git, "https://github.com/davisp/jiffy", {tag, "1.0.5"}}},
{jose, ".*", {git, "https://github.com/potatosalad/erlang-jose", {tag, "1.9.0"}}},
{eimp, ".*", {git, "https://github.com/processone/eimp", {tag, "1.0.14"}}},
{mqtree, ".*", {git, "https://github.com/processone/mqtree", {tag, "1.0.7"}}},
{p1_acme, ".*", {git, "https://github.com/processone/p1_acme.git", {tag, "1.0.5"}}},
{base64url, ".*", {git, "https://github.com/dvv/base64url.git", {tag, "v1.0"}}},
{if_var_true, stun, {stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.31"}}}},
{if_var_true, sip, {esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.32"}}}},
{if_var_true, mysql, {p1_mysql, ".*", {git, "https://github.com/processone/p1_mysql",
{tag, "1.0.14"}}}},
{if_var_true, pgsql, {p1_pgsql, ".*", {git, "https://github.com/processone/p1_pgsql",
{tag, "1.1.9"}}}},
{if_var_true, sqlite, {sqlite3, ".*", {git, "https://github.com/processone/erlang-sqlite3",
{tag, "1.1.6"}}}},
{if_var_true, pam, {epam, ".*", {git, "https://github.com/processone/epam",
{tag, "1.0.7"}}}},
{if_var_true, zlib, {ezlib, ".*", {git, "https://github.com/processone/ezlib",
{tag, "1.0.7"}}}},
%% Elixir support, needed to run tests
{if_var_true, elixir, {elixir, ".*", {git, "https://github.com/elixir-lang/elixir",
{tag, {if_version_above, "17", "v1.4.4", "v1.1.1"}}}}},
%% TODO: When modules are fully migrated to new structure and mix, we will not need anymore rebar_elixir_plugin
{if_not_rebar3, {if_var_true, elixir, {rebar_elixir_plugin, ".*",
{git, "https://github.com/processone/rebar_elixir_plugin", "0.1.0"}}}},
{if_var_true, tools, {luerl, ".*", {git, "https://github.com/rvirding/luerl",
{tag, "v0.3"}}}},
{if_var_true, redis, {eredis, ".*", {git, "https://github.com/wooga/eredis",
{tag, "v1.0.8"}}}}]}.
{lager, ".*", {git, "https://github.com/erlang-lager/lager", {tag, "3.6.10"}}},
{if_var_true, tools,
{luerl, ".*", {git, "https://github.com/rvirding/luerl", {tag, "v0.3"}}}},
{mqtree, ".*", {git, "https://github.com/processone/mqtree", {tag, "1.0.11"}}},
{p1_acme, ".*", {git, "https://github.com/processone/p1_acme.git", {tag, "1.0.10"}}},
{if_var_true, mysql,
{p1_mysql, ".*", {git, "https://github.com/processone/p1_mysql", {tag, "1.0.17"}}}},
{p1_oauth2, ".*", {git, "https://github.com/processone/p1_oauth2", {tag, "0.6.8"}}},
{if_var_true, pgsql,
{p1_pgsql, ".*", {git, "https://github.com/processone/p1_pgsql", {tag, "1.1.10"}}}},
{p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.21"}}},
{pkix, ".*", {git, "https://github.com/processone/pkix", {tag, "1.0.7"}}},
{if_not_rebar3, %% Needed because modules are not fully migrated to new structure and mix
{if_var_true, elixir,
{rebar_elixir_plugin, ".*", {git, "https://github.com/processone/rebar_elixir_plugin", "0.1.0"}}}},
{if_var_true, sqlite,
{sqlite3, ".*", {git, "https://github.com/processone/erlang-sqlite3", {tag, "v1.1.6"}}}},
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.24"}}},
{if_var_true, stun,
{stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.40"}}}},
{xmpp, ".*", {git, "https://github.com/processone/xmpp", {tag, "1.5.1"}}},
{yconf, ".*", {git, "https://github.com/processone/yconf", {tag, "1.0.9"}}}
]}.
{gitonly_deps, [elixir, luerl]}.
{if_var_true, latest_deps,
{floating_deps, [cache_tab,
fast_tls,
stringprep,
fast_xml,
esip,
stun,
fast_yaml,
xmpp,
p1_utils,
p1_mysql,
p1_pgsql,
p1_oauth2,
epam,
ezlib,
eimp,
epam,
esip,
ezlib,
fast_tls,
fast_xml,
fast_yaml,
mqtree,
p1_acme,
p1_mysql,
p1_oauth2,
p1_pgsql,
p1_utils,
pkix,
yconf,
p1_acme]}}.
sqlite3,
stringprep,
stun,
xmpp,
yconf]}}.
{erl_first_files, ["src/ejabberd_sql_pt.erl", "src/ejabberd_config.erl",
"src/gen_mod.erl", "src/mod_muc_room.erl",
@@ -86,21 +91,22 @@
{erl_opts, [nowarn_deprecated_function,
{i, "include"},
{i, "deps/fast_xml/include"},
{i, "deps/xmpp/include"},
{i, "deps/p1_utils/include"},
{if_version_above, "20", {d, 'DEPRECATED_GET_STACKTRACE'}},
{if_version_below, "21", {d, 'USE_OLD_HTTP_URI'}},
{if_version_below, "22", {d, 'LAGER'}},
{if_version_below, "23", {d, 'USE_OLD_CRYPTO_HMAC'}},
{if_version_below, "23", {d, 'USE_OLD_PG2'}},
{if_var_match, db_type, mssql, {d, 'mssql'}},
{if_var_false, debug, no_debug_info},
{if_var_true, debug, debug_info},
{if_var_true, elixir, {d, 'ELIXIR_ENABLED'}},
{if_var_true, hipe, native},
{if_var_true, new_sql_schema, {d, 'NEW_SQL_SCHEMA'}},
{if_var_true, roster_gateway_workaround, {d, 'ROSTER_GATWAY_WORKAROUND'}},
{if_var_true, sip, {d, 'SIP'}},
{if_var_true, stun, {d, 'STUN'}},
{if_version_above, "20", {d, 'DEPRECATED_GET_STACKTRACE'}},
{if_version_below, "22", {d, 'LAGER'}},
{if_var_true, roster_gateway_workaround, {d, 'ROSTER_GATWAY_WORKAROUND'}},
{if_var_match, db_type, mssql, {d, 'mssql'}},
{if_var_true, elixir, {d, 'ELIXIR_ENABLED'}},
{if_var_true, new_sql_schema, {d, 'NEW_SQL_SCHEMA'}},
{if_var_true, hipe, native},
{if_have_fun, {erl_error, format_exception, 6}, {d, 'HAVE_ERL_ERROR'}},
{if_have_fun, {erl_error, format_exception, 6}, {d, 'HAVE_ERL_ERROR'}},
{if_rebar3, {extra_src_dirs, [sql]}},
{src_dirs, [src,
{if_var_true, tools, tools},
{if_var_true, elixir, include}]}]}.
@@ -108,14 +114,17 @@
{deps_erl_opts, [{if_var_true, hipe, native}]}.
{if_rebar3, {plugins, [rebar3_hex, {provider_asn1, "0.2.0"}]}}.
{if_rebar3, {project_plugins, [configure_deps]}}.
{if_not_rebar3, {plugins, [
deps_erl_opts, override_deps_versions2, override_opts, configure_deps,
{if_var_true, elixir, rebar_elixir_compiler},
{if_var_true, elixir, rebar_exunit}
]}}.
{if_var_true, elixir,
{lib_dirs, ["deps/elixir/lib"]}}.
{if_rebar3, {if_var_true, elixir,
{project_app_dirs, [".", "elixir/lib"]}}}.
{if_not_rebar3, {if_var_true, elixir,
{lib_dirs, ["deps/elixir/lib"]}}}.
{if_var_true, elixir,
{src_dirs, ["include"]}}.
@@ -130,21 +139,18 @@
{xref_exclusions, [
"(\"gen_transport\":_/_)",
"(\"eprof\":_/_)",
{if_var_false, mysql, "(\".*mysql.*\":_/_)"},
{if_var_false, pgsql, "(\".*pgsql.*\":_/_)"},
{if_var_false, pam, "(\"epam\":_/_)"},
{if_var_false, zlib, "(\"ezlib\":_/_)"},
{if_var_false, http, "(\"lhttpc\":_/_)"},
{if_var_false, odbc, "(\"odbc\":_/_)"},
{if_var_false, sqlite, "(\"sqlite3\":_/_)"},
{if_var_false, elixir, "(\"Elixir.*\":_/_)"},
{if_var_false, redis, "(\"eredis\":_/_)"}]}.
{if_var_false, http, "(\"lhttpc\":_/_)"},
{if_var_false, mysql, "(\".*mysql.*\":_/_)"},
{if_var_false, odbc, "(\"odbc\":_/_)"},
{if_var_false, pam, "(\"epam\":_/_)"},
{if_var_false, pgsql, "(\".*pgsql.*\":_/_)"},
{if_var_false, redis, "(\"eredis\":_/_)"},
{if_var_false, sqlite, "(\"sqlite3\":_/_)"},
{if_var_false, zlib, "(\"ezlib\":_/_)"}]}.
{eunit_compile_opts, [{i, "tools"},
{i, "include"},
{i, "deps/p1_utils/include"},
{i, "deps/fast_xml/include"},
{i, "deps/xmpp/include"}]}.
{i, "include"}]}.
{cover_enabled, true}.
{cover_export_enabled, true}.
@@ -153,14 +159,14 @@
{overrides, [
{del, [{erl_opts, [warnings_as_errors]}]}]}.
{post_hook_configure, [{"fast_tls", []},
{"stringprep", []},
{"fast_yaml", []},
{"eimp", []},
{if_var_true, sip, {"esip", []}},
{"fast_xml", [{if_var_true, full_xml, "--enable-full-xml"}]},
{post_hook_configure, [{"eimp", []},
{if_var_true, pam, {"epam", []}},
{if_var_true, zlib, {"ezlib", []}}]}.
{if_var_true, sip, {"esip", []}},
{if_var_true, zlib, {"ezlib", []}},
{"fast_tls", []},
{"fast_xml", [{if_var_true, full_xml, "--enable-full-xml"}]},
{"fast_yaml", []},
{"stringprep", []}]}.
%% Local Variables:
%% mode: erlang
+10 -5
View File
@@ -196,9 +196,14 @@ AppendList2 = fun(Append) ->
end,
Rebar3DepsFilter =
fun(DepsList) ->
lists:map(fun({DepName, _, {git, _, {tag, Version}}}) ->
{DepName, Version};
fun(DepsList, GitOnlyDeps) ->
lists:map(fun({DepName, _, {git, _, {tag, Version}}} = Dep) ->
case lists:member(DepName, GitOnlyDeps) of
true ->
Dep;
_ ->
{DepName, Version}
end;
(Dep) ->
Dep
end, DepsList)
@@ -367,8 +372,8 @@ Rules = [
AppendList2(ProcssXrefExclusions), [], []},
{[deps], [floating_deps], true,
ProcessFloatingDeps, [], []},
{[deps], IsRebar3,
Rebar3DepsFilter, []},
{[deps], [gitonly_deps], IsRebar3,
Rebar3DepsFilter, [], []},
{[deps], SystemDeps /= false,
GlobalDepsFilter, []}
],
+1 -1
View File
@@ -209,7 +209,7 @@ WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW
CREATE TABLE [dbo].[pubsub_item] (
[nodeid] [bigint] NULL,
[itemid] [varchar] (255) NOT NULL,
[publisher] [text] NOT NULL,
[publisher] [varchar] (250) NOT NULL,
[creation] [varchar] (32) NOT NULL,
[modification] [varchar] (32) NOT NULL,
[payload] [text] NOT NULL DEFAULT ''
+4 -4
View File
@@ -107,8 +107,8 @@ match_acl(_Host, {shared_group, {G, H}}, #{usr := {U, S, _}}) ->
end;
match_acl(Host, {shared_group, G}, Map) ->
match_acl(Host, {shared_group, {G, Host}}, Map);
match_acl(_Host, {user_regexp, {UR, S}}, #{usr := {U, S, _}}) ->
match_regexp(U, UR);
match_acl(_Host, {user_regexp, {UR, S1}}, #{usr := {U, S2, _}}) ->
S1 == S2 andalso match_regexp(U, UR);
match_acl(_Host, {user_regexp, UR}, #{usr := {U, S, _}}) ->
ejabberd_router:is_my_host(S) andalso match_regexp(U, UR);
match_acl(_Host, {server_regexp, SR}, #{usr := {_, S, _}}) ->
@@ -117,8 +117,8 @@ match_acl(_Host, {resource_regexp, RR}, #{usr := {_, _, R}}) ->
match_regexp(R, RR);
match_acl(_Host, {node_regexp, {UR, SR}}, #{usr := {U, S, _}}) ->
match_regexp(U, UR) andalso match_regexp(S, SR);
match_acl(_Host, {user_glob, {UR, S}}, #{usr := {U, S, _}}) ->
match_regexp(U, UR);
match_acl(_Host, {user_glob, {UR, S1}}, #{usr := {U, S2, _}}) ->
S1 == S2 andalso match_regexp(U, UR);
match_acl(_Host, {user_glob, UR}, #{usr := {U, S, _}}) ->
ejabberd_router:is_my_host(S) andalso match_regexp(U, UR);
match_acl(_Host, {server_glob, SR}, #{usr := {_, S, _}}) ->
+9 -3
View File
@@ -151,7 +151,7 @@ get_commands_spec() ->
module = ?MODULE, function = set_loglevel,
args_desc = ["Desired logging level: none | emergency | alert | critical "
"| error | warning | notice | info | debug"],
args_example = [debug],
args_example = ["debug"],
args = [{loglevel, string}],
result = {res, rescode}},
@@ -208,6 +208,9 @@ get_commands_spec() ->
#ejabberd_commands{name = join_cluster, tags = [cluster],
desc = "Join this node into the cluster handled by Node",
longdesc = "This command works only with ejabberdctl, "
"not mod_http_api or other code that runs inside the "
"same ejabberd node that will be joined.",
module = ?MODULE, function = join_cluster,
args_desc = ["Nodename of the node to join"],
args_example = [<<"ejabberd1@machine7">>],
@@ -215,8 +218,11 @@ get_commands_spec() ->
result = {res, rescode}},
#ejabberd_commands{name = leave_cluster, tags = [cluster],
desc = "Remove and shutdown Node from the running cluster",
longdesc = "This command can be run from any running node of the cluster, "
"even the node to be removed.",
longdesc = "This command can be run from any running "
"node of the cluster, even the node to be removed. "
"In the removed node, this command works only when "
"using ejabberdctl, not mod_http_api or other code that "
"runs inside the same ejabberd node that will leave.",
module = ?MODULE, function = leave_cluster,
args_desc = ["Nodename of the node to kick from the cluster"],
args_example = [<<"ejabberd1@machine8">>],
+51 -33
View File
@@ -33,7 +33,7 @@
set_password/3, check_password/4,
check_password/6, check_password_with_authmodule/4,
check_password_with_authmodule/6, try_register/3,
get_users/0, get_users/1, password_to_scram/1,
get_users/0, get_users/1, password_to_scram/2,
get_users/2, import_info/0,
count_users/1, import/5, import_start/2,
count_users/2, get_password/2,
@@ -48,7 +48,7 @@
-export([auth_modules/1, convert_to_scram/1]).
-include("scram.hrl").
-include_lib("xmpp/include/scram.hrl").
-include("logger.hrl").
-define(SALT_LENGTH, 16).
@@ -197,16 +197,21 @@ plain_password_required(Server) ->
-spec store_type(binary()) -> plain | scram | external.
store_type(Server) ->
lists:foldl(
fun(_, external) -> external;
(M, scram) ->
case M:store_type(Server) of
external -> external;
_ -> scram
end;
(M, plain) ->
M:store_type(Server)
end, plain, auth_modules(Server)).
case auth_modules(Server) of
[ejabberd_auth_anonymous] -> external;
Modules ->
lists:foldl(
fun(ejabberd_auth_anonymous, Type) -> Type;
(_, external) -> external;
(M, scram) ->
case M:store_type(Server) of
external -> external;
_ -> scram
end;
(M, plain) ->
M:store_type(Server)
end, plain, Modules)
end.
-spec check_password(binary(), binary(), binary(), binary()) -> boolean().
check_password(User, AuthzId, Server, Password) ->
@@ -554,7 +559,7 @@ db_try_register(User, Server, Password, Mod) ->
case erlang:function_exported(Mod, try_register, 3) of
true ->
Password1 = case Mod:store_type(Server) of
scram -> password_to_scram(Password);
scram -> password_to_scram(Server, Password);
_ -> Password
end,
Ret = case use_cache(Mod, Server) of
@@ -579,7 +584,7 @@ db_set_password(User, Server, Password, Mod) ->
case erlang:function_exported(Mod, set_password, 3) of
true ->
Password1 = case Mod:store_type(Server) of
scram -> password_to_scram(Password);
scram -> password_to_scram(Server, Password);
_ -> Password
end,
Ret = case use_cache(Mod, Server) of
@@ -605,6 +610,7 @@ db_get_password(User, Server, Mod) ->
false when UseCache ->
case ets_cache:lookup(cache_tab(Mod), {User, Server}) of
{ok, exists} -> error;
not_found -> error;
Other -> Other
end;
false ->
@@ -621,20 +627,29 @@ db_user_exists(User, Server, Mod) ->
case db_get_password(User, Server, Mod) of
{ok, _} ->
true;
not_found ->
false;
error ->
case {Mod:store_type(Server), use_cache(Mod, Server)} of
{external, true} ->
case ets_cache:lookup(
cache_tab(Mod), {User, Server},
fun() ->
case Mod:user_exists(User, Server) of
{CacheTag, true} -> {CacheTag, {ok, exists}};
{CacheTag, false} -> {CacheTag, error};
{_, {error, _}} = Err -> Err
end
end) of
Val = case ets_cache:lookup(cache_tab(Mod), {User, Server}, error) of
error ->
ets_cache:update(cache_tab(Mod), {User, Server}, {ok, exists},
fun() ->
case Mod:user_exists(User, Server) of
{CacheTag, true} -> {CacheTag, {ok, exists}};
{CacheTag, false} -> {CacheTag, not_found};
{_, {error, _}} = Err -> Err
end
end);
Other ->
Other
end,
case Val of
{ok, _} ->
true;
not_found ->
false;
error ->
false;
{error, _} = Err ->
@@ -743,25 +758,28 @@ is_password_scram_valid(Password, Scram) ->
false;
_ ->
IterationCount = Scram#scram.iterationcount,
Hash = Scram#scram.hash,
Salt = base64:decode(Scram#scram.salt),
SaltedPassword = scram:salted_password(Password, Salt, IterationCount),
StoredKey = scram:stored_key(scram:client_key(SaltedPassword)),
SaltedPassword = scram:salted_password(Hash, Password, Salt, IterationCount),
StoredKey = scram:stored_key(Hash, scram:client_key(Hash, SaltedPassword)),
base64:decode(Scram#scram.storedkey) == StoredKey
end.
password_to_scram(Password) ->
password_to_scram(Password, ?SCRAM_DEFAULT_ITERATION_COUNT).
password_to_scram(Host, Password) ->
password_to_scram(Host, Password, ?SCRAM_DEFAULT_ITERATION_COUNT).
password_to_scram(#scram{} = Password, _IterationCount) ->
password_to_scram(_Host, #scram{} = Password, _IterationCount) ->
Password;
password_to_scram(Password, IterationCount) ->
password_to_scram(Host, Password, IterationCount) ->
Hash = ejabberd_option:auth_scram_hash(Host),
Salt = p1_rand:bytes(?SALT_LENGTH),
SaltedPassword = scram:salted_password(Password, Salt, IterationCount),
StoredKey = scram:stored_key(scram:client_key(SaltedPassword)),
ServerKey = scram:server_key(SaltedPassword),
SaltedPassword = scram:salted_password(Hash, Password, Salt, IterationCount),
StoredKey = scram:stored_key(Hash, scram:client_key(Hash, SaltedPassword)),
ServerKey = scram:server_key(Hash, SaltedPassword),
#scram{storedkey = base64:encode(StoredKey),
serverkey = base64:encode(ServerKey),
salt = base64:encode(Salt),
hash = Hash,
iterationcount = IterationCount}.
%%%----------------------------------------------------------------------
@@ -928,7 +946,7 @@ convert_to_scram(Server) ->
fun({U, S}) ->
case get_password(U, S) of
Pass when is_binary(Pass) ->
SPass = password_to_scram(Pass),
SPass = password_to_scram(Server, Pass),
set_password(U, S, SPass);
_ ->
ok
+1 -1
View File
@@ -45,7 +45,7 @@
plain_password_required/1]).
-include("logger.hrl").
-include("jid.hrl").
-include_lib("xmpp/include/jid.hrl").
start(Host) ->
ejabberd_hooks:add(sm_register_connection_hook, Host,
+6 -5
View File
@@ -34,7 +34,7 @@
user_exists/2, use_cache/1
]).
-include("xmpp.hrl").
-include_lib("xmpp/include/xmpp.hrl").
-include("logger.hrl").
%%%----------------------------------------------------------------------
@@ -102,10 +102,11 @@ check_jwt_token(User, Server, Token) ->
error ->
false;
{ok, SJID} ->
try
JID = jid:decode(SJID),
(JID#jid.luser == User) andalso
(JID#jid.lserver == Server)
try jid:decode(SJID) of
JID ->
(JID#jid.luser == User) andalso
(JID#jid.lserver == Server) andalso
ejabberd_hooks:run_fold(check_decoded_jwt, Server, true, [Fields, Signature, User])
catch error:{bad_jid, _} ->
false
end
+24 -7
View File
@@ -37,7 +37,7 @@
-export([need_transform/1, transform/1]).
-include("logger.hrl").
-include("scram.hrl").
-include_lib("xmpp/include/scram.hrl").
-include("ejabberd_auth.hrl").
-record(reg_users_counter, {vhost = <<"">> :: binary(),
@@ -180,6 +180,9 @@ count_users(Server, _) ->
get_password(User, Server) ->
case mnesia:dirty_read(passwd, {User, Server}) of
[#passwd{password = {scram, SK, SEK, Salt, IC}}] ->
{cache, {ok, #scram{storedkey = SK, serverkey = SEK,
salt = Salt, hash = sha, iterationcount = IC}}};
[#passwd{password = Password}] ->
{cache, {ok, Password}};
_ ->
@@ -204,7 +207,8 @@ remove_user(User, Server) ->
need_transform(#reg_users_counter{}) ->
false;
need_transform({passwd, {U, S}, Pass}) ->
if is_binary(Pass) ->
case Pass of
_ when is_binary(Pass) ->
case store_type(S) of
scram ->
?INFO_MSG("Passwords in Mnesia table 'passwd' "
@@ -213,7 +217,7 @@ need_transform({passwd, {U, S}, Pass}) ->
plain ->
false
end;
is_record(Pass, scram) ->
{scram, _, _, _, _} ->
case store_type(S) of
scram ->
false;
@@ -225,7 +229,19 @@ need_transform({passwd, {U, S}, Pass}) ->
"would *fail*", []),
false
end;
is_list(U) orelse is_list(S) orelse is_list(Pass) ->
#scram{} ->
case store_type(S) of
scram ->
false;
plain ->
?WARNING_MSG("Some passwords were stored in the database "
"as SCRAM, but 'auth_password_format' "
"is not configured as 'scram': some "
"authentication mechanisms such as DIGEST-MD5 "
"would *fail*", []),
false
end;
_ when is_list(U) orelse is_list(S) orelse is_list(Pass) ->
?INFO_MSG("Mnesia table 'passwd' will be converted to binary", []),
true
end.
@@ -255,14 +271,15 @@ transform(#passwd{us = {U, S}, password = Password} = P)
[U, S]),
P;
_ ->
Scram = ejabberd_auth:password_to_scram(Password),
Scram = ejabberd_auth:password_to_scram(S, Password),
P#passwd{password = Scram}
end;
plain ->
P
end;
transform(#passwd{password = Password} = P)
when is_record(Password, scram) ->
transform(#passwd{password = {scram, _, _, _, _}} = P) ->
P;
transform(#passwd{password = #scram{}} = P) ->
P.
import(LServer, [LUser, Password, _TimeStamp]) ->
+40 -21
View File
@@ -35,7 +35,7 @@
remove_user/2, store_type/1, plain_password_required/1,
export/1, which_users_exists/2]).
-include("scram.hrl").
-include_lib("xmpp/include/scram.hrl").
-include("logger.hrl").
-include("ejabberd_sql_pt.hrl").
-include("ejabberd_auth.hrl").
@@ -56,16 +56,19 @@ store_type(Server) ->
ejabberd_auth:password_format(Server).
set_password(User, Server, Password) ->
F = fun() ->
if is_record(Password, scram) ->
set_password_scram_t(
User, Server,
Password#scram.storedkey, Password#scram.serverkey,
Password#scram.salt, Password#scram.iterationcount);
true ->
set_password_t(User, Server, Password)
end
end,
F =
fun() ->
case Password of
#scram{hash = Hash, storedkey = SK, serverkey = SEK,
salt = Salt, iterationcount = IC} ->
SK2 = scram_hash_encode(Hash, SK),
set_password_scram_t(
User, Server,
SK2, SEK, Salt, IC);
_ ->
set_password_t(User, Server, Password)
end
end,
case ejabberd_sql:sql_transaction(Server, F) of
{atomic, _} ->
{cache, {ok, Password}};
@@ -74,14 +77,17 @@ set_password(User, Server, Password) ->
end.
try_register(User, Server, Password) ->
Res = if is_record(Password, scram) ->
add_user_scram(
Server, User,
Password#scram.storedkey, Password#scram.serverkey,
Password#scram.salt, Password#scram.iterationcount);
true ->
add_user(Server, User, Password)
end,
Res =
case Password of
#scram{hash = Hash, storedkey = SK, serverkey = SEK,
salt = Salt, iterationcount = IC} ->
SK2 = scram_hash_encode(Hash, SK),
add_user_scram(
Server, User,
SK2, SEK, Salt, IC);
_ ->
add_user(Server, User, Password)
end,
case Res of
{updated, 1} -> {cache, {ok, Password}};
_ -> {nocache, {error, exists}}
@@ -106,9 +112,15 @@ get_password(User, Server) ->
{selected, [{Password, <<>>, <<>>, 0}]} ->
{cache, {ok, Password}};
{selected, [{StoredKey, ServerKey, Salt, IterationCount}]} ->
{cache, {ok, #scram{storedkey = StoredKey,
{Hash, SK} = case StoredKey of
<<"sha256:", Rest/binary>> -> {sha256, Rest};
<<"sha512:", Rest/binary>> -> {sha512, Rest};
Other -> {sha, Other}
end,
{cache, {ok, #scram{storedkey = SK,
serverkey = ServerKey,
salt = Salt,
hash = Hash,
iterationcount = IterationCount}}};
{selected, []} ->
{cache, error};
@@ -126,6 +138,13 @@ remove_user(User, Server) ->
-define(BATCH_SIZE, 1000).
scram_hash_encode(Hash, StoreKey) ->
case Hash of
sha -> StoreKey;
sha256 -> <<"sha256:", StoreKey/binary>>;
sha512 -> <<"sha512:", StoreKey/binary>>
end.
set_password_scram_t(LUser, LServer,
StoredKey, ServerKey, Salt, IterationCount) ->
?SQL_UPSERT_T(
@@ -282,7 +301,7 @@ export(_Server) ->
"password=%(Password)s"])];
(Host, #passwd{us = {LUser, LServer}, password = #scram{} = Scram})
when LServer == Host ->
StoredKey = Scram#scram.storedkey,
StoredKey = scram_hash_encode(Scram#scram.hash, Scram#scram.storedkey),
ServerKey = Scram#scram.serverkey,
Salt = Scram#scram.salt,
IterationCount = Scram#scram.iterationcount,
+1 -1
View File
@@ -43,7 +43,7 @@
code_change/4]).
-include("logger.hrl").
-include("xmpp.hrl").
-include_lib("xmpp/include/xmpp.hrl").
-include("ejabberd_http.hrl").
-include("bosh.hrl").
+71 -44
View File
@@ -43,11 +43,11 @@
process_closed/2, process_terminated/2, process_info/2]).
%% API
-export([get_presence/1, set_presence/2, resend_presence/1, resend_presence/2,
open_session/1, call/3, cast/2, send/2, close/1, close/2, stop/1,
open_session/1, call/3, cast/2, send/2, close/1, close/2, stop_async/1,
reply/2, copy_state/2, set_timeout/2, route/2, format_reason/2,
host_up/1, host_down/1, send_ws_ping/1, bounce_message_queue/2]).
-include("xmpp.hrl").
-include_lib("xmpp/include/xmpp.hrl").
-include("logger.hrl").
-include("mod_roster.hrl").
-include("translate.hrl").
@@ -110,10 +110,9 @@ close(Ref) ->
close(Ref, Reason) ->
xmpp_stream_in:close(Ref, Reason).
-spec stop(pid()) -> ok;
(state()) -> no_return().
stop(Ref) ->
xmpp_stream_in:stop(Ref).
-spec stop_async(pid()) -> ok.
stop_async(Pid) ->
xmpp_stream_in:stop_async(Pid).
-spec send(pid(), xmpp_element()) -> ok;
(state(), xmpp_element()) -> state().
@@ -181,10 +180,9 @@ host_down(Host) ->
%% Copies content of one c2s state to another.
%% This is needed for session migration from one pid to another.
-spec copy_state(state(), state()) -> state().
copy_state(#{owner := Owner} = NewState,
#{jid := JID, resource := Resource, sid := {Time, _},
auth_module := AuthModule, lserver := LServer,
pres_a := PresA} = OldState) ->
copy_state(NewState,
#{jid := JID, resource := Resource, auth_module := AuthModule,
lserver := LServer, pres_a := PresA} = OldState) ->
State1 = case OldState of
#{pres_last := Pres, pres_timestamp := PresTS} ->
NewState#{pres_last => Pres, pres_timestamp => PresTS};
@@ -194,7 +192,6 @@ copy_state(#{owner := Owner} = NewState,
Conn = get_conn_type(State1),
State2 = State1#{jid => JID, resource => Resource,
conn => Conn,
sid => {Time, Owner},
auth_module => AuthModule,
pres_a => PresA},
ejabberd_hooks:run_fold(c2s_copy_session, LServer, State2, [OldState]).
@@ -285,7 +282,8 @@ process_auth_result(#{sasl_mech := Mech,
State.
process_closed(State, Reason) ->
stop(State#{stop_reason => Reason}).
stop_async(self()),
State#{stop_reason => Reason}.
process_terminated(#{sid := SID, socket := Socket,
jid := JID, user := U, server := S, resource := R} = State,
@@ -293,17 +291,17 @@ process_terminated(#{sid := SID, socket := Socket,
Status = format_reason(State, Reason),
?INFO_MSG("(~ts) Closing c2s session for ~ts: ~ts",
[xmpp_socket:pp(Socket), jid:encode(JID), Status]),
Pres = #presence{type = unavailable,
from = JID,
to = jid:remove_resource(JID)},
State1 = case maps:is_key(pres_last, State) of
true ->
Pres = #presence{type = unavailable,
from = JID,
to = jid:remove_resource(JID)},
ejabberd_sm:close_session_unset_presence(SID, U, S, R,
Status),
broadcast_presence_unavailable(State, Pres);
broadcast_presence_unavailable(State, Pres, true);
false ->
ejabberd_sm:close_session(SID, U, S, R),
State
broadcast_presence_unavailable(State, Pres, false)
end,
bounce_message_queue(SID, JID),
State1;
@@ -375,18 +373,28 @@ unauthenticated_stream_features(#{lserver := LServer}) ->
authenticated_stream_features(#{lserver := LServer}) ->
ejabberd_hooks:run_fold(c2s_post_auth_features, LServer, [], [LServer]).
sasl_mechanisms(Mechs, #{lserver := LServer} = State) ->
sasl_mechanisms(Mechs, #{lserver := LServer, stream_encrypted := Encrypted} = State) ->
Type = ejabberd_auth:store_type(LServer),
Mechs1 = ejabberd_option:disable_sasl_mechanisms(LServer),
ScramHash = ejabberd_option:auth_scram_hash(LServer),
ShaAv = Type == plain orelse (Type == scram andalso ScramHash == sha),
Sha256Av = Type == plain orelse (Type == scram andalso ScramHash == sha256),
Sha512Av = Type == plain orelse (Type == scram andalso ScramHash == sha512),
%% I re-created it from cyrsasl ets magic, but I think it's wrong
%% TODO: need to check before 18.09 release
lists:filter(
fun(<<"ANONYMOUS">>) ->
ejabberd_auth_anonymous:is_sasl_anonymous_enabled(LServer);
(<<"DIGEST-MD5">>) -> Type == plain;
(<<"SCRAM-SHA-1">>) -> Type /= external;
(<<"SCRAM-SHA-1">>) -> ShaAv;
(<<"SCRAM-SHA-1-PLUS">>) -> ShaAv andalso Encrypted;
(<<"SCRAM-SHA-256">>) -> Sha256Av;
(<<"SCRAM-SHA-256-PLUS">>) -> Sha256Av andalso Encrypted;
(<<"SCRAM-SHA-512">>) -> Sha512Av;
(<<"SCRAM-SHA-512-PLUS">>) -> Sha512Av andalso Encrypted;
(<<"PLAIN">>) -> true;
(<<"X-OAUTH2">>) -> true;
(<<"X-OAUTH2">>) -> [ejabberd_auth_anonymous] /= ejabberd_auth:auth_modules(LServer);
(<<"EXTERNAL">>) -> maps:get(tls_verify, State, false);
(_) -> false
end, Mechs -- Mechs1).
@@ -491,7 +499,11 @@ handle_authenticated_packet(Pkt, #{lserver := LServer, jid := JID,
#iq{type = set, sub_els = [_]} ->
try xmpp:try_subtag(Pkt2, #xmpp_session{}) of
#xmpp_session{} ->
send(State2, xmpp:make_iq_result(Pkt2));
% It seems that some client are expecting to have response
% to session request be sent from server jid, let's make
% sure it is that.
Pkt3 = xmpp:set_to(Pkt2, jid:make(<<>>, LServer, <<>>)),
send(State2, xmpp:make_iq_result(Pkt3));
_ ->
check_privacy_then_route(State2, Pkt2)
catch _:{xmpp_codec, Why} ->
@@ -730,7 +742,7 @@ process_self_presence(#{lserver := LServer, sid := SID,
_ = ejabberd_sm:unset_presence(SID, U, S, R, Status),
{Pres1, State1} = ejabberd_hooks:run_fold(
c2s_self_presence, LServer, {Pres, State}, []),
State2 = broadcast_presence_unavailable(State1, Pres1),
State2 = broadcast_presence_unavailable(State1, Pres1, true),
maps:remove(pres_last, maps:remove(pres_timestamp, State2));
process_self_presence(#{lserver := LServer} = State,
#presence{type = available} = Pres) ->
@@ -751,28 +763,39 @@ update_priority(#{sid := SID, user := U, server := S, resource := R},
Priority = get_priority_from_presence(Pres),
ejabberd_sm:set_presence(SID, U, S, R, Priority, Pres).
-spec broadcast_presence_unavailable(state(), presence()) -> state().
broadcast_presence_unavailable(#{jid := JID, pres_a := PresA} = State, Pres) ->
-spec broadcast_presence_unavailable(state(), presence(), boolean()) -> state().
broadcast_presence_unavailable(#{jid := JID, pres_a := PresA} = State, Pres,
BroadcastToRoster) ->
#jid{luser = LUser, lserver = LServer} = JID,
BareJID = jid:remove_resource(JID),
Items1 = ejabberd_hooks:run_fold(roster_get, LServer,
[], [{LUser, LServer}]),
BareJID = jid:tolower(jid:remove_resource(JID)),
Items1 = case BroadcastToRoster of
true ->
Roster = ejabberd_hooks:run_fold(roster_get, LServer,
[], [{LUser, LServer}]),
lists:foldl(
fun(#roster{jid = LJID, subscription = Sub}, Acc)
when Sub == both; Sub == from ->
maps:put(LJID, 1, Acc);
(_, Acc) ->
Acc
end, #{BareJID => 1}, Roster);
_ ->
#{BareJID => 1}
end,
Items2 = ?SETS:fold(
fun(LJID, Items) ->
[#roster{jid = LJID, subscription = from}|Items]
end, Items1, PresA),
JIDs = lists:foldl(
fun(#roster{jid = LJID, subscription = Sub}, Tos)
when Sub == both orelse Sub == from ->
To = jid:make(LJID),
P = xmpp:set_to(Pres, jid:make(LJID)),
case privacy_check_packet(State, P, out) of
allow -> [To|Tos];
deny -> Tos
end;
(_, Tos) ->
Tos
end, [BareJID], Items2),
fun(LJID, Acc) ->
maps:put(LJID, 1, Acc)
end, Items1, PresA),
JIDs = lists:filtermap(
fun(LJid) ->
To = jid:make(LJid),
P = xmpp:set_to(Pres, To),
case privacy_check_packet(State, P, out) of
allow -> {true, To};
deny -> false
end
end, maps:keys(Items2)),
route_multiple(State, JIDs, Pres),
State#{pres_a => ?SETS:new()}.
@@ -937,7 +960,11 @@ fix_from_to(Pkt, #{jid := JID}) when ?is_stanza(Pkt) ->
{U, S, _} -> jid:replace_resource(JID, From#jid.resource);
_ -> From
end,
xmpp:set_from_to(Pkt, From1, JID)
To1 = case xmpp:get_to(Pkt) of
#jid{lresource = <<>>} = To2 -> To2;
_ -> JID
end,
xmpp:set_from_to(Pkt, From1, To1)
end;
fix_from_to(Pkt, _State) ->
Pkt.
@@ -991,4 +1018,4 @@ listen_options() ->
{tls_verify, false},
{zlib, false},
{max_stanza_size, infinity},
{max_fsm_queue, 5000}].
{max_fsm_queue, 10000}].
+1 -1
View File
@@ -42,7 +42,7 @@
host_up/1, host_down/1,
config_reloaded/0, process_iq/1]).
-include("xmpp.hrl").
-include_lib("xmpp/include/xmpp.hrl").
-include("logger.hrl").
-include("ejabberd_http.hrl").
-include("translate.hrl").
+1 -1
View File
@@ -1,5 +1,5 @@
%%%-------------------------------------------------------------------
%%% @author Evgeny Khramtsov <ekhramtsov@process-one.net>
%%% Author : Evgeny Khramtsov <ekhramtsov@process-one.net>
%%% Created : 5 Jul 2017 by Evgeny Khramtsov <ekhramtsov@process-one.net>
%%%
%%%
-201
View File
@@ -23,190 +23,6 @@
%%%
%%%----------------------------------------------------------------------
%%% @headerfile "ejabberd_commands.hrl"
%%% @doc Management of ejabberd commands.
%%%
%%% An ejabberd command is an abstract function identified by a name,
%%% with a defined number and type of calling arguments and type of
%%% result, that can be defined in any Erlang module and executed
%%% using any valid frontend.
%%%
%%%
%%% == Define a new ejabberd command ==
%%%
%%% ejabberd commands can be defined and registered in
%%% any Erlang module.
%%%
%%% Some commands are procedures; and their purpose is to perform an
%%% action in the server, so the command result is only some result
%%% code or result tuple. Other commands are inspectors, and their
%%% purpose is to gather some information about the server and return
%%% a detailed response: it can be integer, string, atom, tuple, list
%%% or a mix of those ones.
%%%
%%% The arguments and result of an ejabberd command are strictly
%%% defined. The number and format of the arguments provided when
%%% calling an ejabberd command must match the definition of that
%%% command. The format of the result provided by an ejabberd command
%%% must be exactly its definition. For example, if a command is said
%%% to return an integer, it must always return an integer (except in
%%% case of a crash).
%%%
%%% If you are developing an Erlang module that will run inside
%%% ejabberd and you want to provide a new ejabberd command to
%%% administer some task related to your module, you only need to:
%%% implement a function, define the command, and register it.
%%%
%%%
%%% === Define a new ejabberd command ===
%%%
%%% An ejabberd command is defined using the Erlang record
%%% 'ejabberd_commands'. This record has several elements that you
%%% must define. Note that 'tags', 'desc' and 'longdesc' are optional.
%%%
%%% For example let's define an ejabberd command 'pow' that gets the
%%% integers 'base' and 'exponent'. Its result will be an integer
%%% 'power':
%%%
%%% <pre>#ejabberd_commands{name = pow, tags = [test],
%%% desc = "Return the power of base for exponent",
%%% longdesc = "This is an example command. The formula is:\n"
%%% " power = base ^ exponent",
%%% module = ?MODULE, function = pow,
%%% args = [{base, integer}, {exponent, integer}],
%%% result = {power, integer}}</pre>
%%%
%%%
%%% === Implement the function associated to the command ===
%%%
%%% Now implement a function in your module that matches the arguments
%%% and result of the ejabberd command.
%%%
%%% For example the function calc_power gets two integers Base and
%%% Exponent. It calculates the power and rounds to an integer:
%%%
%%% <pre>calc_power(Base, Exponent) ->
%%% PowFloat = math:pow(Base, Exponent),
%%% round(PowFloat).</pre>
%%%
%%% Since this function will be called by ejabberd_commands, it must
%%% be exported.
%%% Add to your module:
%%% <pre>-export([calc_power/2]).</pre>
%%%
%%% Only some types of result formats are allowed.
%%% If the format is defined as 'rescode', then your function must return:
%%% ok | true | atom()
%%% where the atoms ok and true as considered positive answers,
%%% and any other response atom is considered negative.
%%%
%%% If the format is defined as 'restuple', then the command must return:
%%% {rescode(), string()}
%%%
%%% If the format is defined as '{list, something()}', then the command
%%% must return a list of something().
%%%
%%%
%%% === Register the command ===
%%%
%%% Define this function and put inside the #ejabberd_command you
%%% defined in the beginning:
%%%
%%% <pre>commands() ->
%%% [
%%%
%%% ].</pre>
%%%
%%% You need to include this header file in order to use the record:
%%%
%%% <pre>-include("ejabberd_commands.hrl").</pre>
%%%
%%% When your module is initialized or started, register your commands:
%%%
%%% <pre>ejabberd_commands:register_commands(commands()),</pre>
%%%
%%% And when your module is stopped, unregister your commands:
%%%
%%% <pre>ejabberd_commands:unregister_commands(commands()),</pre>
%%%
%%% That's all! Now when your module is started, the command will be
%%% registered and any frontend can access it. For example:
%%%
%%% <pre>$ ejabberdctl help pow
%%%
%%% Command Name: pow
%%%
%%% Arguments: base::integer
%%% exponent::integer
%%%
%%% Returns: power::integer
%%%
%%% Tags: test
%%%
%%% Description: Return the power of base for exponent
%%%
%%% This is an example command. The formula is:
%%% power = base ^ exponent
%%%
%%% $ ejabberdctl pow 3 4
%%% 81
%%% </pre>
%%%
%%%
%%% == Execute an ejabberd command ==
%%%
%%% ejabberd commands are mean to be executed using any valid
%%% frontend. An ejabberd commands is implemented in a regular Erlang
%%% function, so it is also possible to execute this function in any
%%% Erlang module, without dealing with the associated ejabberd
%%% commands.
%%%
%%%
%%% == Frontend to ejabberd commands ==
%%%
%%% Currently there are two frontends to ejabberd commands: the shell
%%% script {@link ejabberd_ctl. ejabberdctl}, and the XML-RPC server
%%% ejabberd_xmlrpc.
%%%
%%%
%%% === ejabberdctl as a frontend to ejabberd commands ===
%%%
%%% It is possible to use ejabberdctl to get documentation of any
%%% command. But ejabberdctl does not support all the argument types
%%% allowed in ejabberd commands, so there are some ejabberd commands
%%% that cannot be executed using ejabberdctl.
%%%
%%% Also note that the ejabberdctl shell administration script also
%%% manages ejabberdctl commands, which are unrelated to ejabberd
%%% commands and can only be executed using ejabberdctl.
%%%
%%%
%%% === ejabberd_xmlrpc as a frontend to ejabberd commands ===
%%%
%%% ejabberd_xmlrpc provides an XML-RPC server to execute ejabberd commands.
%%% ejabberd_xmlrpc is a contributed module published in ejabberd-modules SVN.
%%%
%%% Since ejabberd_xmlrpc does not provide any method to get documentation
%%% of the ejabberd commands, please use ejabberdctl to know which
%%% commands are available, and their usage.
%%%
%%% The number and format of the arguments provided when calling an
%%% ejabberd command must match the definition of that command. Please
%%% make sure the XML-RPC call provides the required arguments, with
%%% the specified format. The order of the arguments in an XML-RPC
%%% call is not important, because all the data is tagged and will be
%%% correctly prepared by ejabberd_xmlrpc before executing the ejabberd
%%% command.
%%% TODO: consider this feature:
%%% All commands are caught. If an error happens, return the restuple:
%%% {error, flattened error string}
%%% This means that ecomm call APIs (ejabberd_ctl, ejabberd_xmlrpc)
%%% need to allows this. And ejabberd_xmlrpc must be prepared to
%%% handle such an unexpected response.
-module(ejabberd_commands).
-author('badlop@process-one.net').
@@ -312,11 +128,6 @@ code_change(_OldVsn, State, _Extra) ->
-spec register_commands([ejabberd_commands()]) -> ok.
%% @doc Register ejabberd commands.
%% If a command is already registered, a warning is printed and the
%% old command is preserved.
%% A registered command is not directly available to be called through
%% ejabberd ReST API. It need to be exposed to be available through API.
register_commands(Commands) ->
lists:foreach(
fun(Command) ->
@@ -330,7 +141,6 @@ register_commands(Commands) ->
-spec unregister_commands([ejabberd_commands()]) -> ok.
%% @doc Unregister ejabberd commands.
unregister_commands(Commands) ->
lists:foreach(
fun(Command) ->
@@ -341,14 +151,11 @@ unregister_commands(Commands) ->
-spec list_commands() -> [{atom(), [aterm()], string()}].
%% @doc Get a list of all the available commands, arguments and description.
list_commands() ->
list_commands(?DEFAULT_VERSION).
-spec list_commands(integer()) -> [{atom(), [aterm()], string()}].
%% @doc Get a list of all the available commands, arguments and
%% description in a given API version.
list_commands(Version) ->
Commands = get_commands_definition(Version),
[{Name, Args, Desc} || #ejabberd_commands{name = Name,
@@ -357,7 +164,6 @@ list_commands(Version) ->
-spec get_command_format(atom()) -> {[aterm()], [{atom(),atom()}], rterm()}.
%% @doc Get the format of arguments and result of a command.
get_command_format(Name) ->
get_command_format(Name, noauth, ?DEFAULT_VERSION).
get_command_format(Name, Version) when is_integer(Version) ->
@@ -383,13 +189,11 @@ get_command_format(Name, Auth, Version) ->
-spec get_command_definition(atom()) -> ejabberd_commands().
%% @doc Get the definition record of a command.
get_command_definition(Name) ->
get_command_definition(Name, ?DEFAULT_VERSION).
-spec get_command_definition(atom(), integer()) -> ejabberd_commands().
%% @doc Get the definition record of a command in a given API version.
get_command_definition(Name, Version) ->
case lists:reverse(
lists:sort(
@@ -409,7 +213,6 @@ get_commands_definition() ->
-spec get_commands_definition(integer()) -> [ejabberd_commands()].
% @doc Returns all commands for a given API version
get_commands_definition(Version) ->
L = lists:reverse(
lists:sort(
@@ -450,15 +253,11 @@ do_execute_command(Command, Arguments) ->
-spec get_tags_commands() -> [{string(), [string()]}].
%% @spec () -> [{Tag::string(), [CommandName::string()]}]
%% @doc Get all the tags and associated commands.
get_tags_commands() ->
get_tags_commands(?DEFAULT_VERSION).
-spec get_tags_commands(integer()) -> [{string(), [string()]}].
%% @spec (integer) -> [{Tag::string(), [CommandName::string()]}]
%% @doc Get all the tags and associated commands in a given API version
get_tags_commands(Version) ->
CommandTags = [{Name, Tags} ||
#ejabberd_commands{name = Name, tags = Tags}
+3 -2
View File
@@ -80,7 +80,7 @@ md_tag(p, V) ->
md_tag(h1, V) ->
[<<"\n\n## ">>, V, <<"\n">>];
md_tag(h2, V) ->
[<<"\n\n### ">>, V, <<"\n">>];
[<<"\n__">>, V, <<"__\n\n">>];
md_tag(strong, V) ->
[<<"*">>, V, <<"*">>];
md_tag(_, V) ->
@@ -460,7 +460,8 @@ generate_md_output(File, RegExp, Languages) ->
Cmds4 = [maybe_add_policy_arguments(Cmd) || Cmd <- Cmds3],
Langs = binary:split(Languages, <<",">>, [global]),
Header = <<"---\ntitle: Administration API reference\ntoc: true\nmenu: Administration API\norder: 40\n"
"// Autogenerated with 'ejabberdctl gen_markdown_doc_for_commands'\n---">>,
"// Autogenerated with 'ejabberdctl gen_markdown_doc_for_commands'\n---\n\n"
"This section describes API of ejabberd version ", (ejabberd_option:version())/binary>>,
Out = lists:map(fun(C) -> gen_doc(C, false, Langs) end, Cmds4),
{ok, Fh} = file:open(File, [write]),
io:format(Fh, "~ts~ts", [Header, Out]),
+22 -4
View File
@@ -102,8 +102,8 @@ transform(_Host, certfiles, CertFiles1, Acc) ->
transform(_Host, acme, ACME, Acc) ->
ACME1 = lists:map(
fun({ca_url, URL} = Opt) ->
case http_uri:parse(binary_to_list(URL)) of
{ok, {_, _, "acme-v01.api.letsencrypt.org", _, _, _}} ->
case misc:uri_parse(URL) of
{ok, _, "acme-v01.api.letsencrypt.org", _, _} ->
NewURL = ejabberd_acme:default_directory_url(),
?WARNING_MSG("ACME directory URL ~ts defined in "
"option acme->ca_url is deprecated "
@@ -245,8 +245,9 @@ filter(_, _, _, _) ->
%%%===================================================================
transform_listener(Opts, Acc) ->
Opts1 = transform_request_handlers(Opts),
Opts2 = remove_inet_options(Opts1),
collect_listener_certfiles(Opts2, Acc).
Opts2 = transform_turn_ip(Opts1),
Opts3 = remove_inet_options(Opts2),
collect_listener_certfiles(Opts3, Acc).
transform_request_handlers(Opts) ->
case lists:keyfind(module, 1, Opts) of
@@ -258,6 +259,14 @@ transform_request_handlers(Opts) ->
Opts
end.
transform_turn_ip(Opts) ->
case lists:keyfind(module, 1, Opts) of
{_, ejabberd_stun} ->
replace_turn_ip(Opts);
_ ->
Opts
end.
replace_request_handlers(Opts) ->
Handlers = proplists:get_value(request_handlers, Opts, []),
Handlers1 =
@@ -322,6 +331,15 @@ remove_xmlrpc_access_commands(Opts) ->
true
end, Opts).
replace_turn_ip(Opts) ->
lists:filtermap(
fun({turn_ip, Val}) ->
warn_replaced_option(turn_ip, turn_ipv4_address),
{true, {turn_ipv4_address, Val}};
(_) ->
true
end, Opts).
remove_inet_options(Opts) ->
lists:filter(
fun({Opt, _}) when Opt == inet; Opt == inet6 ->
+10 -66
View File
@@ -23,33 +23,14 @@
%%%
%%%----------------------------------------------------------------------
%%% @headerfile "ejabberd_ctl.hrl"
%%% @doc Management of ejabberdctl commands and frontend to ejabberd commands.
%%%
%%% An ejabberdctl command is an abstract function identified by a
%%% name, with a defined number of calling arguments, that can be
%%% defined in any Erlang module and executed using ejabberdctl
%%% administration script.
%%%
%%% Note: strings cannot have blankspaces
%%%
%%% Does not support commands that have arguments with ctypes: list, tuple
%%%
%%% TODO: Update the guide
%%% TODO: Mention this in the release notes
%%% Note: the commands with several words use now the underline: _
%%% It is still possible to call the commands with dash: -
%%% but this is deprecated, and may be removed in a future version.
-module(ejabberd_ctl).
-behaviour(gen_server).
-author('alexey@process-one.net').
-export([start/0, start_link/0, process/1, process2/2,
register_commands/3, unregister_commands/3]).
-export([start/0, start_link/0, process/1, process2/2]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
@@ -111,8 +92,6 @@ start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
init([]) ->
ets:new(ejabberd_ctl_cmds, [named_table, set, public]),
ets:new(ejabberd_ctl_host_cmds, [named_table, set, public]),
{ok, #state{}}.
handle_call(Request, From, State) ->
@@ -133,30 +112,10 @@ terminate(_Reason, _State) ->
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%-----------------------------
%% ejabberdctl Command management
%%-----------------------------
register_commands(CmdDescs, Module, Function) ->
ets:insert(ejabberd_ctl_cmds, CmdDescs),
ejabberd_hooks:add(ejabberd_ctl_process,
Module, Function, 50),
ok.
unregister_commands(CmdDescs, Module, Function) ->
lists:foreach(fun(CmdDesc) ->
ets:delete_object(ejabberd_ctl_cmds, CmdDesc)
end, CmdDescs),
ejabberd_hooks:delete(ejabberd_ctl_process,
Module, Function, 50),
ok.
%%-----------------------------
%% Process
%%-----------------------------
-spec process([string()]) -> non_neg_integer().
process(Args) ->
process(Args, ?DEFAULT_VERSION).
@@ -295,7 +254,7 @@ process2(Args, AccessCommands, Auth, Version) ->
%% Command calling
%%-----------------------------
%% @spec (Args::[string()], Auth, AccessCommands) -> string() | integer() | {string(), integer()}
%% @spec (Args::[string()], Auth, AccessCommands, Version) -> string() | integer() | {string(), integer()}
try_run_ctp(Args, Auth, AccessCommands, Version) ->
try ejabberd_hooks:run_fold(ejabberd_ctl_process, false, [Args]) of
false when Args /= [] ->
@@ -316,7 +275,7 @@ try_run_ctp(Args, Auth, AccessCommands, Version) ->
{io_lib:format("Error in ejabberd ctl process: '~p' ~p", [Error, Why]), ?STATUS_USAGE}
end.
%% @spec (Args::[string()], Auth, AccessCommands) -> string() | integer() | {string(), integer()}
%% @spec (Args::[string()], Auth, AccessCommands, Version) -> string() | integer() | {string(), integer()}
try_call_command(Args, Auth, AccessCommands, Version) ->
try call_command(Args, Auth, AccessCommands, Version) of
{Reason, wrong_command_arguments} ->
@@ -340,7 +299,7 @@ try_call_command(Args, Auth, AccessCommands, Version) ->
?STATUS_ERROR}
end.
%% @spec (Args::[string()], Auth, AccessCommands) -> string() | integer() | {string(), integer()} | {error, ErrorType}
%% @spec (Args::[string()], Auth, AccessCommands, Version) -> string() | integer() | {string(), integer()} | {error, ErrorType}
call_command([CmdString | Args], Auth, _AccessCommands, Version) ->
CmdStringU = ejabberd_regexp:greplace(
list_to_binary(CmdString), <<"-">>, <<"_">>),
@@ -472,7 +431,9 @@ make_status(ok) -> ?STATUS_SUCCESS;
make_status(true) -> ?STATUS_SUCCESS;
make_status(Code) when is_integer(Code), Code > 255 -> ?STATUS_ERROR;
make_status(Code) when is_integer(Code), Code > 0 -> Code;
make_status(_Error) -> ?STATUS_ERROR.
make_status(Error) ->
io:format("Error: ~p~n", [Error]),
?STATUS_ERROR.
get_list_commands(Version) ->
try ejabberd_commands:list_commands(Version) of
@@ -507,13 +468,6 @@ is_supported_args(Args) ->
end,
Args).
get_list_ctls() ->
case catch ets:tab2list(ejabberd_ctl_cmds) of
{'EXIT', _} -> [];
Cs -> [{NameArgs, [], Desc} || {NameArgs, Desc} <- Cs]
end.
%%-----------------------------
%% Print help
%%-----------------------------
@@ -539,8 +493,7 @@ print_usage(HelpMode, MaxC, ShCode, Version) ->
{"restart", [], "Restart ejabberd"},
{"help", ["[--tags [tag] | com?*]"], "Show help (try: ejabberdctl help help)"},
{"mnesia", ["[info]"], "show information of Mnesia system"}] ++
get_list_commands(Version) ++
get_list_ctls(),
get_list_commands(Version),
print(
["Usage: ", ?B("ejabberdctl"), " [--no-timeout] [--node ", ?U("nodename"), "] [--version ", ?U("api_version"), "] ",
@@ -742,7 +695,7 @@ print_usage_help(MaxC, ShCode) ->
%% Print usage command
%%-----------------------------
%% @spec (CmdSubString::string(), MaxC::integer(), ShCode::boolean()) -> ok
%% @spec (CmdSubString::string(), MaxC::integer(), ShCode::boolean(), Version) -> ok
print_usage_commands2(CmdSubString, MaxC, ShCode, Version) ->
%% Get which command names match this substring
AllCommandsNames = [atom_to_list(Name) || {Name, _, _} <- ejabberd_commands:list_commands(Version)],
@@ -785,7 +738,7 @@ filter_commands_regexp(All, Glob) ->
end,
All).
%% @spec (Cmd::string(), MaxC::integer(), ShCode::boolean()) -> ok
%% @spec (Cmd::string(), MaxC::integer(), ShCode::boolean(), Version) -> ok
print_usage_command(Cmd, MaxC, ShCode, Version) ->
Name = list_to_atom(Cmd),
C = ejabberd_commands:get_command_definition(Name, Version),
@@ -872,12 +825,3 @@ disable_logging() ->
disable_logging() ->
logger:set_primary_config(level, none).
-endif.
%%-----------------------------
%% Command management
%%-----------------------------
%%+++
%% Struct(Integer res) create_account(Struct(String user, String server, String password))
%%format_usage_xmlrpc(ArgsDef, ResultDef) ->
%% ["aaaa bbb ccc"].
+4 -3
View File
@@ -69,10 +69,11 @@ man(Lang) ->
catch _:undef -> []
end
end, ejabberd_config:callback_modules(all)),
Version = binary_to_list(ejabberd_option:version()),
Options =
["TOP LEVEL OPTIONS",
"-----------------",
tr(Lang, ?T("This section describes top level options of ejabberd.")),
"This section describes top level options of ejabberd "++Version,
io_lib:nl()] ++
lists:flatmap(
fun(Opt) ->
@@ -92,7 +93,7 @@ man(Lang) ->
"MODULES",
"-------",
"[[modules]]",
tr(Lang, ?T("This section describes options of all ejabberd modules.")),
"This section describes options of all modules in ejabberd "++Version,
io_lib:nl()] ++
lists:flatmap(
fun({M, Descr, DocOpts, Backends, Example}) ->
@@ -111,7 +112,7 @@ man(Lang) ->
"LISTENERS",
"-------",
"[[listeners]]",
tr(Lang, ?T("This section describes options of all ejabberd listeners.")),
"This section describes options of all listeners in ejabberd "++Version,
io_lib:nl(),
"TODO"],
AsciiData =
+13 -6
View File
@@ -37,7 +37,7 @@
-export([init/3]).
-include("logger.hrl").
-include("xmpp.hrl").
-include_lib("xmpp/include/xmpp.hrl").
-include("ejabberd_http.hrl").
-include_lib("kernel/include/file.hrl").
@@ -193,7 +193,13 @@ receive_headers(#state{trail = Trail} = State) ->
Socket = State#state.socket,
Data = SockMod:recv(Socket, 0, 300000),
case Data of
{error, _} -> ok;
{error, closed} when State#state.request_method == undefined ->
% socket closed without receiving anything in it
ok;
{error, Error} ->
?DEBUG("Error when retrieving http headers ~p: ~p",
[State#state.sockmod, Error]),
ok;
{ok, D} ->
parse_headers(State#state{trail = <<Trail/binary, D/binary>>})
end.
@@ -386,7 +392,7 @@ extract_path_query(#state{request_method = Method,
{'EXIT', _Reason} -> [];
LQ -> LQ
end,
{State, {LPath, LQuery, <<"">>}}
{State, {LPath, LQuery, <<"">>, Path}}
end;
extract_path_query(#state{request_method = Method,
request_path = {abs_path, Path},
@@ -402,7 +408,7 @@ extract_path_query(#state{request_method = Method,
{LPath, _Query} ->
case Method of
'PUT' ->
{State, {LPath, [], Trail}};
{State, {LPath, [], Trail, Path}};
'POST' ->
case recv_data(State) of
{ok, Data} ->
@@ -410,7 +416,7 @@ extract_path_query(#state{request_method = Method,
{'EXIT', _Reason} -> [];
LQ -> LQ
end,
{State, {LPath, LQuery, Data}};
{State, {LPath, LQuery, Data, Path}};
error ->
{State, false}
end
@@ -451,7 +457,7 @@ process_request(#state{request_method = Method,
case extract_path_query(State) of
{State2, false} ->
{State2, make_bad_request(State)};
{State2, {LPath, LQuery, Data}} ->
{State2, {LPath, LQuery, Data, RawPath}} ->
PeerName = case SockPeer of
none ->
case SockMod of
@@ -471,6 +477,7 @@ process_request(#state{request_method = Method,
IP = analyze_ip_xff(IPHere, XFF),
Request = #request{method = Method,
path = LPath,
raw_path = RawPath,
q = LQuery,
auth = Auth,
length = Length,
+6 -3
View File
@@ -36,7 +36,7 @@
-include("logger.hrl").
-include("xmpp.hrl").
-include_lib("xmpp/include/xmpp.hrl").
-include("ejabberd_http.hrl").
@@ -364,5 +364,8 @@ parsed_items(List) ->
-spec route_text(pid(), binary()) -> ok.
route_text(Pid, Data) ->
Pid ! {text, Data},
ok.
Pid ! {text_with_reply, Data, self()},
receive
{text_reply, Pid} ->
ok
end.
+1 -1
View File
@@ -34,7 +34,7 @@
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-include("xmpp.hrl").
-include_lib("xmpp/include/xmpp.hrl").
-include("logger.hrl").
-include("ejabberd_stacktrace.hrl").
+41 -12
View File
@@ -105,10 +105,18 @@ init({_, _, Transport} = EndPoint, Module, AllOpts) ->
-spec init(endpoint(), module(), opts(), [gen_tcp:option()]) -> ok.
init({Port, _, udp} = EndPoint, Module, Opts, SockOpts) ->
case gen_udp:open(Port, [binary,
{Port2, ExtraOpts} = case Port of
<<"unix:", Path/binary>> ->
SO = lists:keydelete(ip, 1, SockOpts),
file:delete(Path),
{0, [{ip, {local, Path}} | SO]};
_ ->
{Port, SockOpts}
end,
case gen_udp:open(Port2, [binary,
{active, false},
{reuseaddr, true} |
SockOpts]) of
ExtraOpts]) of
{ok, Socket} ->
case inet:sockname(Socket) of
{ok, {Addr, Port1}} ->
@@ -174,15 +182,22 @@ init({Port, _, tcp} = EndPoint, Module, Opts, SockOpts) ->
-spec listen_tcp(inet:port_number(), [gen_tcp:option()]) ->
{ok, inet:socket()} | {error, system_limit | inet:posix()}.
listen_tcp(Port, SockOpts) ->
Res = gen_tcp:listen(Port, [binary,
{Port2, ExtraOpts} = case Port of
<<"unix:", Path/binary>> ->
SO = lists:keydelete(ip, 1, SockOpts),
file:delete(Path),
{0, [{ip, {local, Path}} | SO]};
_ ->
{Port, SockOpts}
end,
Res = gen_tcp:listen(Port2, [binary,
{packet, 0},
{active, false},
{reuseaddr, true},
{nodelay, true},
{send_timeout, ?TCP_SEND_TIMEOUT},
{send_timeout_close, true},
{keepalive, true} |
SockOpts]),
{keepalive, true} | ExtraOpts]),
case Res of
{ok, ListenSocket} ->
{ok, ListenSocket};
@@ -226,6 +241,8 @@ accept(ListenSocket, Module, State, Sup, Interval, Proxy, Arity) ->
?ERROR_MSG("(~w) Proxy protocol parsing failed: ~ts",
[ListenSocket, format_error(Err)]),
gen_tcp:close(Socket);
{undefined, undefined} ->
gen_tcp:close(Socket);
{{Addr, Port}, {PAddr, PPort}} = SP ->
%% THIS IS WRONG
State2 = [{sock_peer_name, SP} | State],
@@ -307,7 +324,12 @@ start_connection(Module, Arity, Socket, State, Sup) ->
Module:accept(Pid),
{ok, Pid};
Err ->
exit(Pid, kill),
case Sup of
undefined ->
exit(Pid, kill);
_ ->
supervisor:terminate_child(Sup, Pid)
end,
Err
end;
Err ->
@@ -459,11 +481,16 @@ format_error(Reason) ->
-spec format_endpoint(endpoint()) -> string().
format_endpoint({Port, IP, _Transport}) ->
IPStr = case tuple_size(IP) of
4 -> inet:ntoa(IP);
8 -> "[" ++ inet:ntoa(IP) ++ "]"
end,
IPStr ++ ":" ++ integer_to_list(Port).
case Port of
Unix when is_binary(Unix) ->
<<"unix:", Unix/binary>>;
_ ->
IPStr = case tuple_size(IP) of
4 -> inet:ntoa(IP);
8 -> "[" ++ inet:ntoa(IP) ++ "]"
end,
IPStr ++ ":" ++ integer_to_list(Port)
end.
-spec format_transport(transport(), opts()) -> string().
format_transport(Transport, Opts) ->
@@ -618,7 +645,9 @@ partition(Fun, Opts) ->
-spec listen_opt_type(atom()) -> econf:validator().
listen_opt_type(port) ->
econf:int(0, 65535);
econf:either(
econf:int(0, 65535),
econf:binary("^unix:.*"));
listen_opt_type(module) ->
econf:beam([[{start, 3}, {start, 2}],
[{start_link, 3}, {start_link, 2}],
+1 -1
View File
@@ -47,7 +47,7 @@
-include("logger.hrl").
-include_lib("stdlib/include/ms_transform.hrl").
-include("xmpp.hrl").
-include_lib("xmpp/include/xmpp.hrl").
-include("ejabberd_stacktrace.hrl").
-include("translate.hrl").
+13 -7
View File
@@ -47,13 +47,6 @@
-export_type([loglevel/0]).
-spec restart() -> ok.
-spec reopen_log() -> ok.
-spec rotate_log() -> ok.
-spec get() -> loglevel().
-spec set(0..5 | loglevel()) -> ok.
-spec flush() -> ok.
%%%===================================================================
%%% API
%%%===================================================================
@@ -173,14 +166,17 @@ do_start(Level) ->
lager:set_loghwm(Handler, LogRateLimit)
end, gen_event:which_handlers(lager_event)).
-spec restart() -> ok.
restart() ->
Level = ejabberd_option:loglevel(),
application:stop(lager),
start(Level).
-spec reopen_log() -> ok.
reopen_log() ->
ok.
-spec rotate_log() -> ok.
rotate_log() ->
catch lager_crash_log ! rotate,
lists:foreach(
@@ -190,6 +186,7 @@ rotate_log() ->
ok
end, gen_event:which_handlers(lager_event)).
-spec get() -> loglevel().
get() ->
Handlers = get_lager_handlers(),
lists:foldl(fun(lager_console_backend, _Acc) ->
@@ -201,6 +198,7 @@ get() ->
end,
none, Handlers).
-spec set(0..5 | loglevel()) -> ok.
set(N) when is_integer(N), N>=0, N=<5 ->
set(convert_loglevel(N));
set(Level) when ?is_loglevel(Level) ->
@@ -241,6 +239,7 @@ get_lager_version() ->
false -> "0.0.0"
end.
-spec flush() -> ok.
flush() ->
application:stop(lager),
application:stop(sasl).
@@ -261,6 +260,7 @@ start(Level) ->
Config = #{max_no_bytes => LogRotateSize,
max_no_files => LogRotateCount,
filesync_repeat_interval => no_repeat,
file_check => 1000,
sync_mode_qlen => 1000,
drop_mode_qlen => 1000,
flush_qlen => 5000},
@@ -297,6 +297,7 @@ start(Level) ->
Err
end.
-spec restart() -> ok.
restart() ->
ok.
@@ -321,16 +322,20 @@ msg() ->
[{logger_formatter, [[logger_formatter, title], ":", io_lib:nl()], []},
msg, io_lib:nl()].
-spec reopen_log() -> ok.
reopen_log() ->
ok.
-spec rotate_log() -> ok.
rotate_log() ->
ok.
-spec get() -> loglevel().
get() ->
#{level := Level} = logger:get_primary_config(),
Level.
-spec set(0..5 | loglevel()) -> ok.
set(N) when is_integer(N), N>=0, N=<5 ->
set(convert_loglevel(N));
set(Level) when ?is_loglevel(Level) ->
@@ -346,6 +351,7 @@ set(Level) when ?is_loglevel(Level) ->
end
end.
-spec flush() -> ok.
flush() ->
lists:foreach(
fun(#{id := HandlerId, module := logger_std_h}) ->
+1 -1
View File
@@ -54,7 +54,7 @@
oauth_add_client_implicit/3,
oauth_remove_client/1]).
-include("xmpp.hrl").
-include_lib("xmpp/include/xmpp.hrl").
-include("logger.hrl").
-include("ejabberd_http.hrl").
-include("ejabberd_web_admin.hrl").
+1 -1
View File
@@ -36,7 +36,7 @@
-include("ejabberd_oauth.hrl").
-include("logger.hrl").
-include("jid.hrl").
-include_lib("xmpp/include/jid.hrl").
init() ->
rest:start(ejabberd_config:get_myname()),
+1 -1
View File
@@ -37,7 +37,7 @@
-include("ejabberd_oauth.hrl").
-include("ejabberd_sql_pt.hrl").
-include("jid.hrl").
-include_lib("xmpp/include/jid.hrl").
-include("logger.hrl").
init() ->
+32
View File
@@ -17,6 +17,7 @@
-export([auth_method/0, auth_method/1]).
-export([auth_opts/0, auth_opts/1]).
-export([auth_password_format/0, auth_password_format/1]).
-export([auth_scram_hash/0, auth_scram_hash/1]).
-export([auth_use_cache/0, auth_use_cache/1]).
-export([c2s_cafile/0, c2s_cafile/1]).
-export([c2s_ciphers/0, c2s_ciphers/1]).
@@ -91,6 +92,8 @@
-export([oom_queue/0]).
-export([oom_watermark/0]).
-export([outgoing_s2s_families/0, outgoing_s2s_families/1]).
-export([outgoing_s2s_ipv4_address/0, outgoing_s2s_ipv4_address/1]).
-export([outgoing_s2s_ipv6_address/0, outgoing_s2s_ipv6_address/1]).
-export([outgoing_s2s_port/0, outgoing_s2s_port/1]).
-export([outgoing_s2s_timeout/0, outgoing_s2s_timeout/1]).
-export([pam_service/0, pam_service/1]).
@@ -136,6 +139,7 @@
-export([sql_connect_timeout/0, sql_connect_timeout/1]).
-export([sql_database/0, sql_database/1]).
-export([sql_keepalive_interval/0, sql_keepalive_interval/1]).
-export([sql_odbc_driver/0, sql_odbc_driver/1]).
-export([sql_password/0, sql_password/1]).
-export([sql_pool_size/0, sql_pool_size/1]).
-export([sql_port/0, sql_port/1]).
@@ -235,6 +239,13 @@ auth_password_format() ->
auth_password_format(Host) ->
ejabberd_config:get_option({auth_password_format, Host}).
-spec auth_scram_hash() -> 'sha' | 'sha256' | 'sha512'.
auth_scram_hash() ->
auth_scram_hash(global).
-spec auth_scram_hash(global | binary()) -> 'sha' | 'sha256' | 'sha512'.
auth_scram_hash(Host) ->
ejabberd_config:get_option({auth_scram_hash, Host}).
-spec auth_use_cache() -> boolean().
auth_use_cache() ->
auth_use_cache(global).
@@ -666,6 +677,20 @@ outgoing_s2s_families() ->
outgoing_s2s_families(Host) ->
ejabberd_config:get_option({outgoing_s2s_families, Host}).
-spec outgoing_s2s_ipv4_address() -> 'undefined' | inet:ip4_address().
outgoing_s2s_ipv4_address() ->
outgoing_s2s_ipv4_address(global).
-spec outgoing_s2s_ipv4_address(global | binary()) -> 'undefined' | inet:ip4_address().
outgoing_s2s_ipv4_address(Host) ->
ejabberd_config:get_option({outgoing_s2s_ipv4_address, Host}).
-spec outgoing_s2s_ipv6_address() -> 'undefined' | inet:ip6_address().
outgoing_s2s_ipv6_address() ->
outgoing_s2s_ipv6_address(global).
-spec outgoing_s2s_ipv6_address(global | binary()) -> 'undefined' | inet:ip6_address().
outgoing_s2s_ipv6_address(Host) ->
ejabberd_config:get_option({outgoing_s2s_ipv6_address, Host}).
-spec outgoing_s2s_port() -> 1..1114111.
outgoing_s2s_port() ->
outgoing_s2s_port(global).
@@ -921,6 +946,13 @@ sql_keepalive_interval() ->
sql_keepalive_interval(Host) ->
ejabberd_config:get_option({sql_keepalive_interval, Host}).
-spec sql_odbc_driver() -> binary().
sql_odbc_driver() ->
sql_odbc_driver(global).
-spec sql_odbc_driver(global | binary()) -> binary().
sql_odbc_driver(Host) ->
ejabberd_config:get_option({sql_odbc_driver, Host}).
-spec sql_password() -> binary().
sql_password() ->
sql_password(global).
+12
View File
@@ -79,6 +79,8 @@ opt_type(auth_opts) ->
end;
opt_type(auth_password_format) ->
econf:enum([plain, scram]);
opt_type(auth_scram_hash) ->
econf:enum([sha, sha256, sha512]);
opt_type(auth_use_cache) ->
econf:bool();
opt_type(c2s_cafile) ->
@@ -271,6 +273,10 @@ opt_type(outgoing_s2s_families) ->
(ipv6) -> inet6
end, L)
end);
opt_type(outgoing_s2s_ipv4_address) ->
econf:ipv4();
opt_type(outgoing_s2s_ipv6_address) ->
econf:ipv6();
opt_type(outgoing_s2s_port) ->
econf:port();
opt_type(outgoing_s2s_timeout) ->
@@ -371,6 +377,8 @@ opt_type(sql_keepalive_interval) ->
econf:timeout(second);
opt_type(sql_password) ->
econf:binary();
opt_type(sql_odbc_driver) ->
econf:binary();
opt_type(sql_pool_size) ->
econf:pos_int();
opt_type(sql_port) ->
@@ -511,6 +519,7 @@ options() ->
fun(Host) -> [ejabberd_config:default_db(Host, ejabberd_auth)] end},
{auth_opts, []},
{auth_password_format, plain},
{auth_scram_hash, sha},
{auth_use_cache,
fun(Host) -> ejabberd_config:get_option({use_cache, Host}) end},
{c2s_cafile, undefined},
@@ -587,6 +596,8 @@ options() ->
{oom_queue, 10000},
{oom_watermark, 80},
{outgoing_s2s_families, [inet, inet6]},
{outgoing_s2s_ipv4_address, undefined},
{outgoing_s2s_ipv6_address, undefined},
{outgoing_s2s_port, 5269},
{outgoing_s2s_timeout, timer:seconds(10)},
{pam_service, <<"ejabberd">>},
@@ -645,6 +656,7 @@ options() ->
{sql_database, undefined},
{sql_keepalive_interval, undefined},
{sql_password, <<"">>},
{sql_odbc_driver, <<"libtdsodbc.so">>}, % default is FreeTDS driver
{sql_pool_size,
fun(Host) ->
case ejabberd_config:get_option({sql_type, Host}) of
+159 -36
View File
@@ -36,14 +36,14 @@ doc() ->
{listen,
#{value => "[Options, ...]",
desc =>
?T("The option for listeners configuration. See "
"<<listeners,Listeners>> section of this document "
?T("The option for listeners configuration. See the "
"http://../listen/[Listen Modules] section "
"for details.")}},
{modules,
#{value => "{Module: Options}",
desc =>
?T("The option for modules configuration. See "
"<<modules,Modules>> section of this document "
"http://../modules/[Modules] section "
"for details.")}},
{loglevel,
#{value =>
@@ -60,32 +60,49 @@ doc() ->
#{value => "timeout()",
desc =>
?T("The time of a cached item to keep in cache. "
"Once it's expired, the corresponding item is "
"erased from cache. The default value is 'one hour'.")}},
"Once it's expired, the corresponding item is "
"erased from cache. The default value is 'one hour'. "
"Several modules have a similar option; and some core "
"ejabberd parts support similar options too, see "
"'auth_cache_life_time', 'oauth_cache_life_time', "
"'router_cache_life_time', and 'sm_cache_life_time'.")}},
{cache_missed,
#{value => "true | false",
desc =>
?T("Whether or not to cache missed lookups. When there is "
"an attempt to lookup for a value in a database and "
"this value is not found and the option is set to 'true', "
"this attempt will be cached and no attempts will be "
"performed until the cache expires (see 'cache_life_time'). "
"Usually you don't want to change it. Default is 'true'.")}},
"an attempt to lookup for a value in a database and "
"this value is not found and the option is set to 'true', "
"this attempt will be cached and no attempts will be "
"performed until the cache expires (see 'cache_life_time'). "
"Usually you don't want to change it. Default is 'true'. "
"Several modules have a similar option; and some core "
"ejabberd parts support similar options too, see "
"'auth_cache_missed', 'oauth_cache_missed', "
"'router_cache_missed', and 'sm_cache_missed'.")}},
{cache_size,
#{value => "pos_integer() | infinity",
desc =>
?T("A maximum number of items (not memory!) in cache. "
"The rule of thumb, for all tables except rosters, "
"you should set it to the number of maximum online "
"users you expect. For roster multiply this number "
"by 20 or so. If the cache size reaches this threshold, "
"it's fully cleared, i.e. all items are deleted, and "
"the corresponding warning is logged. You should avoid "
"frequent cache clearance, because this degrades "
"performance. The default value is '1000'.")}},
?T("A maximum number of items (not memory!) in cache. "
"The rule of thumb, for all tables except rosters, "
"you should set it to the number of maximum online "
"users you expect. For roster multiply this number "
"by 20 or so. If the cache size reaches this threshold, "
"it's fully cleared, i.e. all items are deleted, and "
"the corresponding warning is logged. You should avoid "
"frequent cache clearance, because this degrades "
"performance. The default value is '1000'. "
"Several modules have a similar option; and some core "
"ejabberd parts support similar options too, see "
"'auth_cache_size', 'oauth_cache_size', "
"'router_cache_size', and 'sm_cache_size'.")}},
{use_cache,
#{value => "true | false",
desc => ?T("Enable or disable cache. The default is 'true'.")}},
desc =>
?T("Enable or disable cache. The default is 'true'. "
"Several modules have a similar option; and some core "
"ejabberd parts support similar options too, see "
"'auth_use_cache', 'oauth_use_cache', 'router_use_cache', "
"and 'sm_use_cache'.")}},
{default_db,
#{value => "mnesia | sql",
desc =>
@@ -93,7 +110,7 @@ doc() ->
"Modules and other components (e.g. authentication) "
"may have its own value. The default value is 'mnesia'.")}},
{default_ram_db,
#{value => "mnesia | sql | redis",
#{value => "mnesia | redis | sql",
desc =>
?T("Default volatile (in-memory) storage for ejabberd. "
"Modules and other components (e.g. session management) "
@@ -236,7 +253,7 @@ doc() ->
{acme,
#{value => ?T("Options"),
desc =>
?T("ACME configuration. ACME is used to automatically "
?T("http://../basic/#acme[ACME] configuration, to automatically "
"obtain SSL certificates for the domains served by ejabberd, "
"which means that certificate requests and renewals are "
"performed to some CA server (aka \"ACME server\") in a fully "
@@ -300,6 +317,13 @@ doc() ->
"'sasl_anon' means that the SASL Anonymous method will be used. "
"'both' means that SASL Anonymous and login anonymous are both "
"enabled. The default value is 'sasl_anon'.")}},
{api_permissions,
#{value => "[Permission, ...]",
desc =>
?T("Define the permissions for API access. Please consult the "
"ejabberd Docs web -> For Developers -> ejabberd ReST API -> "
"https://docs.ejabberd.im/developer/ejabberd-api/permissions/"
"[API Permissions].")}},
{append_host_config,
#{value => "{Host: Options}",
desc =>
@@ -330,6 +354,13 @@ doc() ->
"considered successful as long as authentication of "
"at least one of the methods succeeds. "
"The default value is '[mnesia]'.")}},
{auth_opts,
#{value => "[Option, ...]",
desc =>
?T("This is used by the contributed module "
"'ejabberd_auth_http' that can be installed from the "
"'ejabberd-contrib' Git repository. Please refer to that "
"module's README file for details.")}},
{auth_password_format,
#{value => "plain | scram",
desc =>
@@ -347,6 +378,13 @@ doc() ->
"value is configured it cannot be changed to plain anymore. "
"This format allows clients to authenticate using: "
"SASL PLAIN and SASL SCRAM-SHA-1.")}},
{auth_scram_hash,
#{value => "sha | sha256 | sha512",
desc =>
?T("Hash algorith that should be used to store password in SCRAM format. "
"You shouldn't change this if you are already have passwords generated "
"with different algorithm - this will make users that have old password "
"being able to use SCRAM auth algorithms.")}},
{auth_use_cache,
#{value => "true | false",
desc =>
@@ -355,11 +393,14 @@ doc() ->
{c2s_cafile,
#{value => ?T("Path"),
desc =>
?T("Full path to a file containing one or more CA certificates "
[?T("Full path to a file containing one or more CA certificates "
"in PEM format. All client certificates should be signed by "
"one of these root CA certificates and should contain the "
"corresponding JID(s) in subjectAltName field. "
"There is no default value.")}},
"corresponding JID(s) in 'subjectAltName' field. "
"There is no default value."), "",
?T("You can use http://../toplevel/#host-config[host_config] to specify this option per-vhost."), "",
?T("To set a specific file per listener, use the listener's http://../listen-options/#cafile[cafile] option. Please notice that 'c2s_cafile' overrides the listener's 'cafile' option."), ""
]}},
{c2s_ciphers,
#{value => "[Cipher, ...]",
desc =>
@@ -400,8 +441,10 @@ doc() ->
{ca_file,
#{value => ?T("Path"),
desc =>
?T("Path to a file of CA root certificates. "
"The default is to use system defined file if possible.")}},
[?T("Path to a file of CA root certificates. "
"The default is to use system defined file if possible."), "",
?T("For server conections, this 'ca_file' option is overriden by the http://../toplevel/#s2s-cafile[s2s_cafile] option."), ""
]}},
{captcha_cmd,
#{value => ?T("Path"),
desc =>
@@ -415,7 +458,8 @@ doc() ->
"any given JID. The option is intended to protect the server "
"from CAPTCHA DoS. The default value is 'infinity'.")}},
{captcha_host,
#{desc => ?T("Deprecated. Use 'captcha_url' instead.")}},
#{value => "String",
desc => ?T("Deprecated. Use 'captcha_url' instead.")}},
{captcha_url,
#{value => ?T("URL"),
desc =>
@@ -453,7 +497,7 @@ doc() ->
desc =>
?T("A list of Erlang nodes to connect on ejabberd startup. "
"This option is mostly intended for ejabberd customization "
"and sofisticated setups. The default value is an empty list.")}},
"and sophisticated setups. The default value is an empty list.")}},
{define_macro,
#{value => "{MacroName: MacroValue}",
desc =>
@@ -516,6 +560,11 @@ doc() ->
#{value => "2..1000",
desc =>
?T("The number of components to balance.")}}]},
{extauth_pool_name,
#{value => ?T("Name"),
desc =>
?T("Define the pool name appendix, so the full pool name will be "
"'extauth_pool_Name'. The default value is the hostname.")}},
{extauth_pool_size,
#{value => ?T("Size"),
desc =>
@@ -527,6 +576,28 @@ doc() ->
desc =>
?T("Indicate in this option the full path to the external "
"authentication script. The script must be executable by ejabberd.")}},
{ext_api_headers,
#{value => "Headers",
desc =>
?T("String of headers (separated with commas ',') that will be "
"provided by ejabberd when sending ReST requests. "
"The default value is an empty string of headers: '\"\"'.")}},
{ext_api_http_pool_size,
#{value => "pos_integer()",
desc =>
?T("Define the size of the HTTP pool, that is, the maximum number "
"of sessions that the ejabberd ReST service will handle "
"simultaneously. The default value is: '100'.")}},
{ext_api_path_oauth,
#{value => "Path",
desc =>
?T("Define the base URI path when performing OAUTH ReST requests. "
"The default value is: '\"/oauth\"'.")}},
{ext_api_url,
#{value => "URL",
desc =>
?T("Define the base URI when performing ReST requests. "
"The default value is: '\"http://localhost/api\"'.")}},
{fqdn,
#{value => ?T("Domain"),
desc =>
@@ -577,6 +648,26 @@ doc() ->
"file 'Filename'. The options that do not match this "
"criteria are not accepted. The default value is to include "
"all options.")}}]},
{jwt_auth_only_rule,
#{value => ?T("AccessName"),
desc =>
?T("This ACL rule defines accounts that can use only this auth "
"method, even if others are also defined in the ejabberd "
"configuration file. In other words: if there are several auth "
"methods enabled for this host (JWT, SQL, ...), users that "
"match this rule can only use JWT. "
"The default value is 'none'.")}},
{jwt_jid_field,
#{value => ?T("FieldName"),
desc =>
?T("By default, the JID is defined in the '\"jid\"' JWT field. "
"This option allows to specify other JWT field name "
"where the JID is defined.")}},
{jwt_key,
#{value => ?T("FilePath"),
desc =>
?T("Path to the file that contains the JWK Key. "
"The default value is 'undefined'.")}},
{language,
#{value => ?T("Language"),
desc =>
@@ -748,7 +839,7 @@ doc() ->
desc =>
{?T("Whether to use 'new' SQL schema. All schemas are located "
"at <https://github.com/processone/ejabberd/tree/~s/sql>. "
"There are two schemas available. The default lecacy schema "
"There are two schemas available. The default legacy schema "
"allows to store one XMPP domain into one ejabberd database. "
"The 'new' schema allows to handle several XMPP domains in a "
"single ejabberd database. Using this 'new' schema is best when "
@@ -780,6 +871,12 @@ doc() ->
desc =>
?T("Same as 'cache_size', but applied to OAuth cache "
"only. If not set, the value from 'cache_size' will be used.")}},
{oauth_client_id_check,
#{value => "allow | db | deny",
desc =>
?T("Define whether the client authentication is always allowed, "
"denied, or it will depend if the client ID is present in the "
"database. The default value is 'allow'.")}},
{oauth_use_cache,
#{value => "true | false",
desc =>
@@ -830,6 +927,18 @@ doc() ->
?T("Specify which address families to try, in what order. "
"The default is '[ipv4, ipv6]' which means it first tries "
"connecting with IPv4, if that fails it tries using IPv6.")}},
{outgoing_s2s_ipv4_address,
#{value => "Address",
desc =>
?T("Specify the IPv4 address that will be used when establishing "
"an outgoing S2S IPv4 connection, for example \"127.0.0.1\". "
"The default value is 'undefined'.")}},
{outgoing_s2s_ipv6_address,
#{value => "Address",
desc =>
?T("Specify the IPv6 address that will be used when establishing "
"an outgoing S2S IPv6 connection, for example "
"\"::FFFF:127.0.0.1\". The default value is 'undefined'.")}},
{outgoing_s2s_port,
#{value => "1..65535",
desc =>
@@ -937,7 +1046,7 @@ doc() ->
?T("Same as 'cache_size', but applied to routing table cache "
"only. If not set, the value from 'cache_size' will be used.")}},
{router_db_type,
#{value => "mnesia | sql | redis",
#{value => "mnesia | redis | sql",
desc =>
?T("Database backend to use for routing information. "
"The default value is picked from 'default_ram_db' option, or "
@@ -963,9 +1072,11 @@ doc() ->
{s2s_cafile,
#{value => ?T("Path"),
desc =>
?T("A path to a file with CA root certificates that will "
"be used to authenticate s2s connections. If not set "
"the value of 'ca_file' will be used.")}},
[?T("A path to a file with CA root certificates that will "
"be used to authenticate s2s connections. If not set, "
"the value of http://../toplevel/#ca-file[ca_file] will be used."), "",
?T("You can use http://../toplevel/#host-config[host_config] to specify this option per-vhost."), ""
]}},
{s2s_ciphers,
#{value => "[Cipher, ...]",
desc =>
@@ -1097,7 +1208,7 @@ doc() ->
?T("Same as 'cache_size', but applied to client sessions table cache "
"only. If not set, the value from 'cache_size' will be used.")}},
{sm_db_type,
#{value => "mnesia | sql | redis",
#{value => "mnesia | redis | sql",
desc =>
?T("Database backend to use for client sessions information. "
"The default value is picked from 'default_ram_db' option, or "
@@ -1108,7 +1219,7 @@ doc() ->
?T("Same as 'use_cache', but applied to client sessions table cache "
"only. If not set, the value from 'use_cache' will be used.")}},
{sql_type,
#{value => "mysql | pgsql | sqlite | mssql | odbc",
#{value => "mssql | mysql | odbc | pgsql | sqlite",
desc =>
?T("The type of an SQL connection. The default is 'odbc'.")}},
{sql_connect_timeout,
@@ -1127,6 +1238,13 @@ doc() ->
?T("An interval to make a dummy SQL request to keep alive the "
"connections to the database. There is no default value, so no "
"keepalive requests are made.")}},
{sql_odbc_driver,
#{value => "Path",
desc =>
?T("Path to the ODBC driver to use to connect to a Microsoft SQL "
"Server database. This option is only valid if the 'sql_type' "
"option is set to 'mssql'. "
"The default value is: 'libtdsodbc.so'")}},
{sql_password,
#{value => ?T("Password"),
desc =>
@@ -1144,6 +1262,11 @@ doc() ->
?T("The port where the SQL server is accepting connections. "
"The default is '3306' for MySQL, '5432' for PostgreSQL and "
"'1433' for MSSQL. The option has no effect for SQLite.")}},
{sql_prepared_statements,
#{value => "true | false",
desc =>
?T("This option is 'true' by default, and is useful to disable "
"prepared statements. The option is valid for PostgreSQL.")}},
{sql_query_timeout,
#{value => "timeout()",
desc =>
+16 -5
View File
@@ -40,9 +40,9 @@
-define(CHUNK_SIZE, 1024*20). %20k
-include("scram.hrl").
-include_lib("xmpp/include/scram.hrl").
-include("logger.hrl").
-include("xmpp.hrl").
-include_lib("xmpp/include/xmpp.hrl").
-include("mod_privacy.hrl").
-include("mod_roster.hrl").
@@ -181,21 +181,32 @@ export_user(User, Server, Fd) ->
{<<"password">>, Pass}],
children = Els})).
format_scram_password(#scram{storedkey = StoredKey, serverkey = ServerKey,
format_scram_password(#scram{hash = Hash, storedkey = StoredKey, serverkey = ServerKey,
salt = Salt, iterationcount = IterationCount}) ->
StoredKeyB64 = base64:encode(StoredKey),
ServerKeyB64 = base64:encode(ServerKey),
SaltB64 = base64:encode(Salt),
IterationCountBin = (integer_to_binary(IterationCount)),
<<"scram:", StoredKeyB64/binary, ",", ServerKeyB64/binary, ",", SaltB64/binary, ",", IterationCountBin/binary>>.
Hash2 = case Hash of
sha -> <<>>;
sha256 -> <<"sha256,">>;
sha512 -> <<"sha512,">>
end,
<<"scram:", Hash2/binary, StoredKeyB64/binary, ",", ServerKeyB64/binary, ",", SaltB64/binary, ",", IterationCountBin/binary>>.
parse_scram_password(PassData) ->
Split = binary:split(PassData, <<",">>, [global]),
[StoredKeyB64, ServerKeyB64, SaltB64, IterationCountBin] = Split,
[Hash, StoredKeyB64, ServerKeyB64, SaltB64, IterationCountBin] =
case Split of
[K1, K2, K3, K4] -> [sha, K1, K2, K3, K4];
[<<"sha256">>, K1, K2, K3, K4] -> [sha256, K1, K2, K3, K4];
[<<"sha512">>, K1, K2, K3, K4] -> [sha512, K1, K2, K3, K4]
end,
#scram{
storedkey = base64:decode(StoredKeyB64),
serverkey = base64:decode(ServerKeyB64),
salt = base64:decode(SaltB64),
hash = Hash,
iterationcount = (binary_to_integer(IterationCountBin))
}.
+1 -1
View File
@@ -1,5 +1,5 @@
%%%-------------------------------------------------------------------
%%% @author Evgeny Khramtsov <ekhramtsov@process-one.net>
%%% Author : Evgeny Khramtsov <ekhramtsov@process-one.net>
%%% Created : 4 Mar 2017 by Evgeny Khramtsov <ekhramtsov@process-one.net>
%%%
%%%
+1 -1
View File
@@ -1,5 +1,5 @@
%%%-------------------------------------------------------------------
%%% @author Evgeny Khramtsov <ekhramtsov@process-one.net>
%%% Author : Evgeny Khramtsov <ekhramtsov@process-one.net>
%%% Created : 6 Apr 2017 by Evgeny Khramtsov <ekhramtsov@process-one.net>
%%%
%%%
+6 -45
View File
@@ -1,7 +1,7 @@
%%%----------------------------------------------------------------------
%%% File : ejabberd_regexp.erl
%%% Author : Badlop
%%% Purpose : Frontend to Re and Regexp OTP modules
%%% Purpose : Frontend to Re OTP module
%%% Created : 8 Dec 2011 by Badlop
%%%
%%%
@@ -25,66 +25,27 @@
-module(ejabberd_regexp).
-export([exec/2, run/2, split/2, replace/3, greplace/3, sh_to_awk/1]).
exec({ReM, ReF, ReA}, {RgM, RgF, RgA}) ->
try apply(ReM, ReF, ReA) catch
error:undef -> apply(RgM, RgF, RgA);
A:B -> {error, {A, B}}
end.
-export([run/2, split/2, replace/3, greplace/3, sh_to_awk/1]).
-spec run(binary(), binary()) -> match | nomatch | {error, any()}.
run(String, Regexp) ->
case exec({re, run, [String, Regexp, [{capture, none}, unicode]]},
{regexp, first_match, [binary_to_list(String),
binary_to_list(Regexp)]})
of
{match, _, _} -> match;
{match, _} -> match;
match -> match;
nomatch -> nomatch;
{error, Error} -> {error, Error}
end.
re:run(String, Regexp, [{capture, none}, unicode]).
-spec split(binary(), binary()) -> [binary()].
split(String, Regexp) ->
case exec({re, split, [String, Regexp, [{return, binary}]]},
{regexp, split, [binary_to_list(String),
binary_to_list(Regexp)]})
of
{ok, FieldList} -> [iolist_to_binary(F) || F <- FieldList];
{error, Error} -> throw(Error);
A -> A
end.
re:split(String, Regexp, [{return, binary}]).
-spec replace(binary(), binary(), binary()) -> binary().
replace(String, Regexp, New) ->
case exec({re, replace, [String, Regexp, New, [{return, binary}]]},
{regexp, sub, [binary_to_list(String),
binary_to_list(Regexp),
binary_to_list(New)]})
of
{ok, NewString, _RepCount} -> iolist_to_binary(NewString);
{error, Error} -> throw(Error);
A -> A
end.
re:replace(String, Regexp, New, [{return, binary}]).
-spec greplace(binary(), binary(), binary()) -> binary().
greplace(String, Regexp, New) ->
case exec({re, replace, [String, Regexp, New, [global, {return, binary}]]},
{regexp, sub, [binary_to_list(String),
binary_to_list(Regexp),
binary_to_list(New)]})
of
{ok, NewString, _RepCount} -> iolist_to_binary(NewString);
{error, Error} -> throw(Error);
A -> A
end.
re:replace(String, Regexp, New, [global, {return, binary}]).
%% This code was copied and adapted from xmerl_regexp.erl
+1 -1
View File
@@ -69,7 +69,7 @@
-include("logger.hrl").
-include("ejabberd_router.hrl").
-include("xmpp.hrl").
-include_lib("xmpp/include/xmpp.hrl").
-include("ejabberd_stacktrace.hrl").
-callback init() -> any().
+1 -1
View File
@@ -42,7 +42,7 @@
terminate/2, code_change/3]).
-include("logger.hrl").
-include("xmpp.hrl").
-include_lib("xmpp/include/xmpp.hrl").
-record(route_multicast, {domain = <<"">> :: binary() | '_',
pid = self() :: pid()}).
+1 -1
View File
@@ -1,5 +1,5 @@
%%%-------------------------------------------------------------------
%%% @author Evgeny Khramtsov <ekhramtsov@process-one.net>
%%% Author : Evgeny Khramtsov <ekhramtsov@process-one.net>
%%% Created : 28 Mar 2017 by Evgeny Khramtsov <ekhramtsov@process-one.net>
%%%
%%%
+1 -1
View File
@@ -1,5 +1,5 @@
%%%-------------------------------------------------------------------
%%% @author Evgeny Khramtsov <ekhramtsov@process-one.net>
%%% Author : Evgeny Khramtsov <ekhramtsov@process-one.net>
%%% Created : 28 Mar 2017 by Evgeny Khramtsov <ekhramtsov@process-one.net>
%%%
%%%
+11 -8
View File
@@ -52,7 +52,7 @@
-export([get_info_s2s_connections/1]).
-include("logger.hrl").
-include("xmpp.hrl").
-include_lib("xmpp/include/xmpp.hrl").
-include("ejabberd_commands.hrl").
-include_lib("stdlib/include/ms_transform.hrl").
-include("ejabberd_stacktrace.hrl").
@@ -319,7 +319,7 @@ host_down(Host) ->
case ejabberd_router:host_of_route(From) of
Host ->
ejabberd_s2s_out:send(Pid, Err),
ejabberd_s2s_out:stop(Pid);
ejabberd_s2s_out:stop_async(Pid);
_ ->
ok
end;
@@ -351,8 +351,11 @@ route(Packet) ->
{ok, Pid} when is_pid(Pid) ->
?DEBUG("Sending to process ~p~n", [Pid]),
#jid{lserver = MyServer} = From,
ejabberd_hooks:run(s2s_send_packet, MyServer, [Packet]),
ejabberd_s2s_out:route(Pid, Packet);
case ejabberd_hooks:run_fold(s2s_send_packet, MyServer, Packet,
[]) of
drop -> ok;
Packet1 -> ejabberd_s2s_out:route(Pid, Packet1)
end;
{error, Reason} ->
Lang = xmpp:get_lang(Packet),
Err = case Reason of
@@ -473,14 +476,14 @@ new_connection(MyServer, Server, From, FromTo,
if Pid1 == Pid ->
ejabberd_s2s_out:connect(Pid);
true ->
ejabberd_s2s_out:stop(Pid)
ejabberd_s2s_out:stop_async(Pid)
end,
[Pid1];
{aborted, Reason} ->
?ERROR_MSG("Failed to register s2s connection ~ts -> ~ts: "
"Mnesia failure: ~p",
[MyServer, Server, Reason]),
ejabberd_s2s_out:stop(Pid),
ejabberd_s2s_out:stop_async(Pid),
[]
end.
@@ -553,13 +556,13 @@ stop_s2s_connections(Err) ->
lists:foreach(
fun({_Id, Pid, _Type, _Module}) ->
ejabberd_s2s_in:send(Pid, Err),
ejabberd_s2s_in:stop(Pid),
ejabberd_s2s_in:stop_async(Pid),
supervisor:terminate_child(ejabberd_s2s_in_sup, Pid)
end, supervisor:which_children(ejabberd_s2s_in_sup)),
lists:foreach(
fun({_Id, Pid, _Type, _Module}) ->
ejabberd_s2s_out:send(Pid, Err),
ejabberd_s2s_out:stop(Pid),
ejabberd_s2s_out:stop_async(Pid),
supervisor:terminate_child(ejabberd_s2s_out_sup, Pid)
end, supervisor:which_children(ejabberd_s2s_out_sup)),
_ = mnesia:clear_table(s2s),
+8 -6
View File
@@ -38,10 +38,10 @@
-export([handle_unexpected_info/2, handle_unexpected_cast/2,
reject_unauthenticated_packet/2, process_closed/2]).
%% API
-export([stop/1, close/1, close/2, send/2, update_state/2, establish/1,
-export([stop_async/1, close/1, close/2, send/2, update_state/2, establish/1,
host_up/1, host_down/1]).
-include("xmpp.hrl").
-include_lib("xmpp/include/xmpp.hrl").
-include("logger.hrl").
-type state() :: xmpp_stream_in:state().
@@ -64,8 +64,9 @@ close(Ref) ->
close(Ref, Reason) ->
xmpp_stream_in:close(Ref, Reason).
stop(Ref) ->
xmpp_stream_in:stop(Ref).
-spec stop_async(pid()) -> ok.
stop_async(Pid) ->
xmpp_stream_in:stop_async(Pid).
accept(Ref) ->
xmpp_stream_in:accept(Ref).
@@ -130,7 +131,8 @@ process_closed(#{server := LServer} = State, Reason) ->
end,
?INFO_MSG("Closing inbound s2s connection ~ts -> ~ts: ~ts",
[RServer, LServer, xmpp_stream_out:format_error(Reason)]),
stop(State).
stop_async(self()),
State.
%%%===================================================================
%%% xmpp_stream_in callbacks
@@ -349,4 +351,4 @@ listen_options() ->
{tls, false},
{tls_compression, false},
{max_stanza_size, infinity},
{max_fsm_queue, 5000}].
{max_fsm_queue, 10000}].
+29 -9
View File
@@ -24,7 +24,7 @@
%% xmpp_stream_out callbacks
-export([tls_options/1, tls_required/1, tls_verify/1, tls_enabled/1,
connect_timeout/1, address_families/1, default_port/1,
connect_options/3, connect_timeout/1, address_families/1, default_port/1,
dns_retries/1, dns_timeout/1,
handle_auth_success/2, handle_auth_failure/3, handle_packet/2,
handle_stream_end/2, handle_stream_downgraded/2,
@@ -36,10 +36,10 @@
-export([process_auth_result/2, process_closed/2, handle_unexpected_info/2,
handle_unexpected_cast/2, process_downgraded/2]).
%% API
-export([start/3, start_link/3, connect/1, close/1, close/2, stop/1, send/2,
-export([start/3, start_link/3, connect/1, close/1, close/2, stop_async/1, send/2,
route/2, establish/1, update_state/2, host_up/1, host_down/1]).
-include("xmpp.hrl").
-include_lib("xmpp/include/xmpp.hrl").
-include("logger.hrl").
-include("translate.hrl").
@@ -79,10 +79,9 @@ close(Ref) ->
close(Ref, Reason) ->
xmpp_stream_out:close(Ref, Reason).
-spec stop(pid()) -> ok;
(state()) -> no_return().
stop(Ref) ->
xmpp_stream_out:stop(Ref).
-spec stop_async(pid()) -> ok.
stop_async(Pid) ->
xmpp_stream_out:stop_async(Pid).
-spec send(pid(), xmpp_element()) -> ok;
(state(), xmpp_element()) -> state().
@@ -150,7 +149,8 @@ process_closed(#{server := LServer, remote_server := RServer,
Reason) ->
?INFO_MSG("Closing outbound s2s connection ~ts -> ~ts: ~ts",
[LServer, RServer, format_error(Reason)]),
stop(State);
stop_async(self()),
State;
process_closed(#{server := LServer, remote_server := RServer} = State,
Reason) ->
Delay = get_delay(),
@@ -187,6 +187,20 @@ tls_verify(#{server_host := ServerHost} = State) ->
tls_enabled(#{server_host := ServerHost}) ->
ejabberd_s2s:tls_enabled(ServerHost).
connect_options(Addr, Opts, #{server_host := ServerHost}) ->
BindAddr = case get_addr_type(Addr) of
inet ->
ejabberd_option:outgoing_s2s_ipv4_address(ServerHost);
inet6 ->
ejabberd_option:outgoing_s2s_ipv6_address(ServerHost)
end,
case BindAddr of
undefined ->
Opts;
_ ->
[{ip, BindAddr} | Opts]
end.
connect_timeout(#{server_host := ServerHost}) ->
ejabberd_option:outgoing_s2s_timeout(ServerHost).
@@ -248,7 +262,9 @@ handle_send(El, Pkt, #{server_host := ServerHost} = State) ->
handle_timeout(#{on_route := Action, lang := Lang} = State) ->
case Action of
bounce -> stop(State);
bounce ->
stop_async(self()),
State;
_ ->
Txt = ?T("Idle connection"),
send(State, xmpp:serr_connection_timeout(Txt, Lang))
@@ -316,6 +332,10 @@ code_change(_OldVsn, State, _Extra) ->
%%%===================================================================
%%% Internal functions
%%%===================================================================
-spec get_addr_type(inet:ip_address()) -> inet:address_family().
get_addr_type({_, _, _, _}) -> inet;
get_addr_type({_, _, _, _, _, _, _, _}) -> inet6.
-spec resend_queue(state()) -> state().
resend_queue(State) ->
queue_fold(
+7 -8
View File
@@ -33,9 +33,9 @@
-export([handle_stream_start/2, handle_auth_success/4, handle_auth_failure/4,
handle_authenticated_packet/2, get_password_fun/1, tls_options/1]).
%% API
-export([send/2, close/1, close/2, stop/1]).
-export([send/2, close/1, close/2, stop_async/1]).
-include("xmpp.hrl").
-include_lib("xmpp/include/xmpp.hrl").
-include("logger.hrl").
-include("translate.hrl").
@@ -59,7 +59,7 @@ stop() ->
lists:foreach(
fun({_Id, Pid, _Type, _Module}) ->
send(Pid, Err),
stop(Pid),
stop_async(Pid),
supervisor:terminate_child(ejabberd_service_sup, Pid)
end, supervisor:which_children(ejabberd_service_sup)),
_ = supervisor:terminate_child(ejabberd_sup, ejabberd_service_sup),
@@ -83,10 +83,9 @@ close(Ref) ->
close(Ref, Reason) ->
xmpp_stream_in:close(Ref, Reason).
-spec stop(pid()) -> ok;
(state()) -> no_return().
stop(Ref) ->
xmpp_stream_in:stop(Ref).
-spec stop_async(pid()) -> ok.
stop_async(Pid) ->
xmpp_stream_in:stop_async(Pid).
%%%===================================================================
%%% xmpp_stream_in callbacks
@@ -303,7 +302,7 @@ listen_options() ->
{tls, false},
{tls_compression, false},
{max_stanza_size, infinity},
{max_fsm_queue, 5000},
{max_fsm_queue, 10000},
{password, undefined},
{hosts, []},
{check_from, true},
+2 -2
View File
@@ -85,7 +85,7 @@
handle_info/2, terminate/2, code_change/3]).
-include("logger.hrl").
-include("xmpp.hrl").
-include_lib("xmpp/include/xmpp.hrl").
-include("ejabberd_commands.hrl").
-include("ejabberd_sm.hrl").
-include("ejabberd_stacktrace.hrl").
@@ -538,7 +538,7 @@ host_down(Host) ->
lists:foreach(
fun(#session{sid = {_, Pid}}) when node(Pid) == node() ->
ejabberd_c2s:send(Pid, Err),
ejabberd_c2s:stop(Pid);
ejabberd_c2s:stop_async(Pid);
(_) ->
ok
end, get_sessions(Mod, Host)),
+13 -48
View File
@@ -51,8 +51,6 @@
sqlite_file/1,
encode_term/1,
decode_term/1,
odbc_config/0,
freetds_config/0,
odbcinst_config/0,
init_mssql/1,
keep_alive/2,
@@ -351,11 +349,11 @@ init([Host]) ->
connecting(connect, #state{host = Host} = State) ->
ConnectRes = case db_opts(Host) of
[mysql | Args] -> apply(fun mysql_connect/8, Args);
[pgsql | Args] -> apply(fun pgsql_connect/8, Args);
[sqlite | Args] -> apply(fun sqlite_connect/1, Args);
[mssql | Args] -> apply(fun odbc_connect/2, Args);
[odbc | Args] -> apply(fun odbc_connect/2, Args)
[mysql | Args] -> apply(fun mysql_connect/8, Args);
[pgsql | Args] -> apply(fun pgsql_connect/8, Args);
[sqlite | Args] -> apply(fun sqlite_connect/1, Args);
[mssql | Args] -> apply(fun odbc_connect/2, Args);
[odbc | Args] -> apply(fun odbc_connect/2, Args)
end,
case ConnectRes of
{ok, Ref} ->
@@ -1036,7 +1034,7 @@ mysql_to_odbc({error, MySQLRes})
when is_list(MySQLRes) ->
{error, list_to_binary(MySQLRes)};
mysql_to_odbc({error, MySQLRes}) ->
{error, p1_mysql:get_result_reason(MySQLRes)};
mysql_to_odbc({error, p1_mysql:get_result_reason(MySQLRes)});
mysql_to_odbc(ok) ->
ok.
@@ -1109,8 +1107,9 @@ db_opts(Host) ->
SSLOpts = get_ssl_opts(Transport, Host),
case Type of
mssql ->
[mssql, <<"DSN=", Host/binary, ";UID=", User/binary,
";PWD=", Pass/binary>>, Timeout];
[mssql, <<"DRIVER=ODBC;SERVER=", Server/binary, ";UID=", User/binary,
";DATABASE=", DB/binary ,";PWD=", Pass/binary,
";PORT=", (integer_to_binary(Port))/binary ,";CLIENT_CHARSET=UTF-8;">>, Timeout];
_ ->
[Type, Server, Port, DB, User, Pass, Timeout, Transport, SSLOpts]
end
@@ -1153,43 +1152,15 @@ get_ssl_opts(tcp, _) ->
[].
init_mssql(Host) ->
Server = ejabberd_option:sql_server(Host),
Port = ejabberd_option:sql_port(Host),
DB = case ejabberd_option:sql_database(Host) of
undefined -> <<"ejabberd">>;
D -> D
end,
FreeTDS = io_lib:fwrite("[~ts]~n"
"\thost = ~ts~n"
"\tport = ~p~n"
"\tclient charset = UTF-8~n"
"\ttds version = 7.1~n",
[Host, Server, Port]),
ODBCINST = io_lib:fwrite("[freetds]~n"
"Description = MSSQL connection~n"
"Driver = libtdsodbc.so~n"
"Setup = libtdsS.so~n"
"UsageCount = 1~n"
"FileUsage = 1~n", []),
ODBCINI = io_lib:fwrite("[~ts]~n"
"Description = MS SQL~n"
"Driver = freetds~n"
"Servername = ~ts~n"
"Database = ~ts~n"
"Port = ~p~n",
[Host, Host, DB, Port]),
?DEBUG("~ts:~n~ts", [freetds_config(), FreeTDS]),
Driver = ejabberd_option:sql_odbc_driver(Host),
ODBCINST = io_lib:fwrite("[ODBC]~n"
"Driver = ~s~n", [Driver]),
?DEBUG("~ts:~n~ts", [odbcinst_config(), ODBCINST]),
?DEBUG("~ts:~n~ts", [odbc_config(), ODBCINI]),
case filelib:ensure_dir(freetds_config()) of
case filelib:ensure_dir(odbcinst_config()) of
ok ->
try
ok = write_file_if_new(freetds_config(), FreeTDS),
ok = write_file_if_new(odbcinst_config(), ODBCINST),
ok = write_file_if_new(odbc_config(), ODBCINI),
os:putenv("ODBCSYSINI", tmp_dir()),
os:putenv("FREETDS", freetds_config()),
os:putenv("FREETDSCONF", freetds_config()),
ok
catch error:{badmatch, {error, Reason} = Err} ->
?ERROR_MSG("Failed to create temporary files in ~ts: ~ts",
@@ -1214,12 +1185,6 @@ tmp_dir() ->
_ -> filename:join(["/tmp", "ejabberd"])
end.
odbc_config() ->
filename:join(tmp_dir(), "odbc.ini").
freetds_config() ->
filename:join(tmp_dir(), "freetds.conf").
odbcinst_config() ->
filename:join(tmp_dir(), "odbcinst.ini").
+19 -1
View File
@@ -558,6 +558,11 @@ make_sql_upsert(Table, ParseRes, Pos) ->
erl_syntax:integer(90100))],
[make_sql_upsert_pgsql901(Table, ParseRes),
erl_syntax:atom(ok)]),
erl_syntax:clause(
[erl_syntax:atom(mysql), erl_syntax:underscore()],
[],
[make_sql_upsert_mysql(Table, ParseRes),
erl_syntax:atom(ok)]),
erl_syntax:clause(
[erl_syntax:underscore(), erl_syntax:underscore()],
none,
@@ -628,6 +633,9 @@ make_sql_upsert_update(Table, ParseRes) ->
State.
make_sql_upsert_insert(Table, ParseRes) ->
make_sql_upsert_insert_replace(Table, ParseRes, "INSERT").
make_sql_upsert_insert_replace(Table, ParseRes, Keyword) ->
Vals =
lists:map(
fun({_Field, _, ST}) ->
@@ -640,7 +648,7 @@ make_sql_upsert_insert(Table, ParseRes) ->
end, ParseRes),
State =
concat_states(
[#state{'query' = [{str, "INSERT INTO "}, {str, Table}, {str, "("}]},
[#state{'query' = [{str, Keyword ++" INTO "}, {str, Table}, {str, "("}]},
join_states(Fields, ", "),
#state{'query' = [{str, ") VALUES ("}]},
join_states(Vals, ", "),
@@ -648,6 +656,16 @@ make_sql_upsert_insert(Table, ParseRes) ->
]),
State.
make_sql_upsert_replace(Table, ParseRes) ->
make_sql_upsert_insert_replace(Table, ParseRes, "REPLACE").
make_sql_upsert_mysql(Table, ParseRes) ->
Replace = make_sql_query(make_sql_upsert_replace(Table, ParseRes)),
erl_syntax:application(
erl_syntax:atom(ejabberd_sql),
erl_syntax:atom(sql_query_t),
[Replace]).
make_sql_upsert_pgsql901(Table, ParseRes0) ->
ParseRes = lists:map(
fun({"family", A2, A3}) -> {"\"family\"", A2, A3};
-2
View File
@@ -84,8 +84,6 @@ stop() ->
ejabberd_hooks:delete(config_reloaded, ?MODULE, config_reloaded, 20).
init([]) ->
file:delete(ejabberd_sql:freetds_config()),
file:delete(ejabberd_sql:odbc_config()),
file:delete(ejabberd_sql:odbcinst_config()),
ejabberd_hooks:add(host_up, ?MODULE, start, 20),
ejabberd_hooks:add(host_down, ?MODULE, stop, 90),
+87 -22
View File
@@ -46,19 +46,26 @@ start_link(_, _, _) ->
fail().
-else.
-export([tcp_init/2, udp_init/2, udp_recv/5, start/3,
start_link/3, accept/1, listen_opt_type/1, listen_options/0]).
start_link/3, accept/1, listen_opt_type/1, listen_options/0,
get_password/2]).
-include("logger.hrl").
-ifndef(LAGER).
-export([stun_filter/2]).
-define(STUN_MAX_LOG_LEVEL, notice). % Drop STUN/TURN info/debug messages.
-endif.
%%%===================================================================
%%% API
%%%===================================================================
tcp_init(Socket, Opts) ->
init_logger(),
ejabberd:start_app(stun),
stun:tcp_init(Socket, prepare_turn_opts(Opts)).
-dialyzer({nowarn_function, udp_init/2}).
udp_init(Socket, Opts) ->
init_logger(),
ejabberd:start_app(stun),
stun:udp_init(Socket, prepare_turn_opts(Opts)).
@@ -74,6 +81,21 @@ start_link(_SockMod, Socket, Opts) ->
accept(_Pid) ->
ok.
get_password(User, Realm) ->
case ejabberd_hooks:run_fold(stun_get_password, <<>>, [User, Realm]) of
Password when byte_size(Password) > 0 ->
Password;
<<>> ->
case ejabberd_auth:get_password_s(User, Realm) of
Password when is_binary(Password) ->
Password;
_ ->
?INFO_MSG("Cannot use hashed password of ~s@~s for "
"STUN/TURN authentication", [User, Realm]),
<<>>
end
end.
%%%===================================================================
%%% Internal functions
%%%===================================================================
@@ -85,27 +107,36 @@ prepare_turn_opts(Opts, _UseTurn = false) ->
set_certfile(Opts);
prepare_turn_opts(Opts, _UseTurn = true) ->
NumberOfMyHosts = length(ejabberd_option:hosts()),
case proplists:get_value(turn_ip, Opts) of
undefined ->
?WARNING_MSG("Option 'turn_ip' is undefined, "
"most likely the TURN relay won't be working "
"properly", []);
_ ->
ok
end,
AuthFun = fun ejabberd_auth:get_password_s/2,
TurnIP = case proplists:get_value(turn_ipv4_address, Opts) of
undefined ->
MyIP = misc:get_my_ipv4_address(),
case MyIP of
{127, _, _, _} ->
?WARNING_MSG("Option 'turn_ipv4_address' is "
"undefined and the server's hostname "
"doesn't resolve to a public IPv4 "
"address, most likely the TURN relay "
"won't be working properly", []);
_ ->
ok
end,
[{turn_ipv4_address, MyIP}];
_ ->
[]
end,
AuthFun = fun ejabberd_stun:get_password/2,
Shaper = proplists:get_value(shaper, Opts, none),
AuthType = proplists:get_value(auth_type, Opts, user),
Realm = case proplists:get_value(auth_realm, Opts) of
undefined when AuthType == user ->
if NumberOfMyHosts > 1 ->
?WARNING_MSG("You have several virtual "
"hosts configured, but option "
"'auth_realm' is undefined and "
"'auth_type' is set to 'user', "
"most likely the TURN relay won't "
"be working properly. Using ~ts as "
"a fallback", [ejabberd_config:get_myname()]);
?INFO_MSG("You have several virtual hosts "
"configured, but option 'auth_realm' is "
"undefined and 'auth_type' is set to "
"'user', so the TURN relay might not be "
"working properly. Using ~ts as a "
"fallback",
[ejabberd_config:get_myname()]);
true ->
ok
end,
@@ -114,8 +145,8 @@ prepare_turn_opts(Opts, _UseTurn = true) ->
[]
end,
MaxRate = ejabberd_shaper:get_max_rate(Shaper),
Opts1 = Realm ++ [{auth_fun, AuthFun},{shaper, MaxRate} |
lists:keydelete(shaper, 1, Opts)],
Opts1 = TurnIP ++ Realm ++ [{auth_fun, AuthFun},{shaper, MaxRate} |
lists:keydelete(shaper, 1, Opts)],
set_certfile(Opts1).
set_certfile(Opts) ->
@@ -135,9 +166,11 @@ set_certfile(Opts) ->
listen_opt_type(use_turn) ->
econf:bool();
listen_opt_type(ip) ->
econf:ip();
listen_opt_type(turn_ipv4_address) ->
econf:ipv4();
listen_opt_type(turn_ip) ->
econf:ipv4();
listen_opt_type(turn_ipv6_address) ->
econf:ipv6();
listen_opt_type(auth_type) ->
econf:enum([anonymous, user]);
listen_opt_type(auth_realm) ->
@@ -150,6 +183,8 @@ listen_opt_type(turn_max_allocations) ->
econf:pos_int(infinity);
listen_opt_type(turn_max_permissions) ->
econf:pos_int(infinity);
listen_opt_type(turn_blacklist) ->
econf:list_or_single(econf:ip_mask());
listen_opt_type(server_name) ->
econf:binary();
listen_opt_type(certfile) ->
@@ -158,7 +193,8 @@ listen_opt_type(certfile) ->
listen_options() ->
[{shaper, none},
{use_turn, false},
{turn_ip, undefined},
{turn_ipv4_address, undefined},
{turn_ipv6_address, undefined},
{auth_type, user},
{auth_realm, undefined},
{tls, false},
@@ -167,5 +203,34 @@ listen_options() ->
{turn_max_port, 65535},
{turn_max_allocations, 10},
{turn_max_permissions, 10},
{turn_blacklist, [<<"2001::/32">>, <<"2002::/16">>]}, % Teredo, 6to4.
{server_name, <<"ejabberd">>}].
-spec init_logger() -> ok.
-ifdef(LAGER).
init_logger() ->
ok.
-else.
init_logger() ->
case logger:add_primary_filter(ejabberd_stun, {fun ?MODULE:stun_filter/2,
?STUN_MAX_LOG_LEVEL}) of
ok ->
ok;
{error, {already_exist, _}} ->
ok
end.
-spec stun_filter(logger:log_event(), logger:level() | term())
-> logger:filter_return().
stun_filter(#{meta := #{domain := [stun | _]}, level := Level}, MaxLevel) ->
case logger:compare_levels(Level, MaxLevel) of
lt ->
stop;
_ ->
ignore
end;
stun_filter(Event, _Extra) ->
Event.
-endif.
-endif.
+1 -1
View File
@@ -33,7 +33,7 @@
-include("logger.hrl").
-include("xmpp.hrl").
-include_lib("xmpp/include/xmpp.hrl").
-include("ejabberd_http.hrl").
+163 -142
View File
@@ -29,13 +29,13 @@
-author('alexey@process-one.net').
-export([process/2, list_users/5,
list_users_in_diapason/5, pretty_print_xml/1,
-export([process/2, list_users/4,
list_users_in_diapason/4, pretty_print_xml/1,
term_to_id/1]).
-include("logger.hrl").
-include("xmpp.hrl").
-include_lib("xmpp/include/xmpp.hrl").
-include("ejabberd_http.hrl").
@@ -95,20 +95,20 @@ get_jid(Auth, HostHTTP, Method) ->
throw({unauthorized, Auth})
end.
get_menu_items(global, cluster, Lang, JID, Base) ->
{_BaseURL, _, Items} = make_server_menu([], [], Lang, JID, Base),
get_menu_items(global, cluster, Lang, JID, Level) ->
{_Base, _, Items} = make_server_menu([], [], Lang, JID, Level),
lists:map(fun ({URI, Name}) ->
{<<Base/binary, URI/binary, "/">>, Name};
{<<URI/binary, "/">>, Name};
({URI, Name, _SubMenu}) ->
{<<Base/binary, URI/binary, "/">>, Name}
{<<URI/binary, "/">>, Name}
end,
Items);
get_menu_items(Host, cluster, Lang, JID, Base) ->
{_BaseURL, _, Items} = make_host_menu(Host, [], Lang, JID, Base),
get_menu_items(Host, cluster, Lang, JID, Level) ->
{_Base, _, Items} = make_host_menu(Host, [], Lang, JID, Level),
lists:map(fun ({URI, Name}) ->
{<<Base/binary, URI/binary, "/">>, Name};
{<<URI/binary, "/">>, Name};
({URI, Name, _SubMenu}) ->
{<<Base/binary, URI/binary, "/">>, Name}
{<<URI/binary, "/">>, Name}
end,
Items).
@@ -123,10 +123,15 @@ get_menu_items(Host, cluster, Lang, JID, Base) ->
%% Items
%% ).
is_allowed_path(Base, {Path, _}, JID) ->
is_allowed_path(Base ++ [Path], JID);
is_allowed_path(Base, {Path, _, _}, JID) ->
is_allowed_path(Base ++ [Path], JID).
is_allowed_path(global, RPath, JID) ->
is_allowed_path([], RPath, JID);
is_allowed_path(Host, RPath, JID) when is_binary(Host) ->
is_allowed_path([<<"server">>, Host], RPath, JID);
is_allowed_path(BasePath, {Path, _}, JID) ->
is_allowed_path(BasePath ++ [Path], JID);
is_allowed_path(BasePath, {Path, _, _}, JID) ->
is_allowed_path(BasePath ++ [Path], JID).
is_allowed_path([<<"admin">> | Path], JID) ->
is_allowed_path(Path, JID);
@@ -134,25 +139,26 @@ is_allowed_path(Path, JID) ->
{HostOfRule, AccessRule} = get_acl_rule(Path, 'GET'),
any_rules_allowed(HostOfRule, AccessRule, JID).
%% @spec(Path) -> URL
%% where Path = [string()]
%% URL = string()
%% Convert ["admin", "user", "tom"] -> "/admin/user/tom/"
%%path_to_url(Path) ->
%% "/" ++ string:join(Path, "/") ++ "/".
%% @spec(URL) -> Path
%% where Path = [string()]
%% URL = string()
%% Convert "admin/user/tom" -> ["admin", "user", "tom"]
url_to_path(URL) -> str:tokens(URL, <<"/">>).
%%%==================================
%%%% process/2
process([<<"server">>, SHost | RPath] = Path,
process(Path, #request{raw_path = RawPath} = Request) ->
Continue = case Path of
[E] ->
binary:match(E, <<".">>) /= nomatch;
_ ->
false
end,
case Continue orelse binary:at(RawPath, size(RawPath) - 1) == $/ of
true ->
process2(Path, Request);
_ ->
{301, [{<<"Location">>, <<RawPath/binary, "/">>}], <<>>}
end.
process2([<<"server">>, SHost | RPath] = Path,
#request{auth = Auth, lang = Lang, host = HostHTTP,
path = RequestPath, method = Method} =
method = Method} =
Request) ->
Host = jid:nameprep(SHost),
case ejabberd_router:is_my_host(Host) of
@@ -160,8 +166,7 @@ process([<<"server">>, SHost | RPath] = Path,
case get_auth_admin(Auth, HostHTTP, Path, Method) of
{ok, {User, Server}} ->
AJID = get_jid(Auth, HostHTTP, Method),
Base = extract_base_path(RequestPath, Path),
process_admin(Base, Host,
process_admin(Host,
Request#request{path = RPath,
us = {User, Server}},
AJID);
@@ -186,15 +191,14 @@ process([<<"server">>, SHost | RPath] = Path,
end;
false -> ejabberd_web:error(not_found)
end;
process(RPath,
process2(RPath,
#request{auth = Auth, lang = Lang, host = HostHTTP,
path = Path, method = Method} =
method = Method} =
Request) ->
Base = extract_base_path(Path, RPath),
case get_auth_admin(Auth, HostHTTP, RPath, Method) of
{ok, {User, Server}} ->
AJID = get_jid(Auth, HostHTTP, Method),
process_admin(Base, global,
process_admin(global,
Request#request{path = RPath,
us = {User, Server}},
AJID);
@@ -268,15 +272,16 @@ get_auth_account2(HostOfRule, AccessRule, User, Server,
%%%==================================
%%%% make_xhtml
make_xhtml(Els, Host, Lang, JID, Base) ->
make_xhtml(Els, Host, cluster, Lang, JID, Base).
make_xhtml(Els, Host, Lang, JID, Level) ->
make_xhtml(Els, Host, cluster, Lang, JID, Level).
%% @spec (Els, Host, Node, Lang, JID) -> {200, [html], xmlelement()}
%% @spec (Els, Host, Node, Lang, JID, Level::integer()) -> {200, [html], xmlelement()}
%% where Host = global | string()
%% Node = cluster | atom()
%% JID = jid()
make_xhtml(Els, Host, Node, Lang, JID, Base) ->
MenuItems = make_navigation(Host, Node, Lang, JID, Base),
make_xhtml(Els, Host, Node, Lang, JID, Level) ->
Base = get_base_path_sum(0, 0, Level),
MenuItems = make_navigation(Host, Node, Lang, JID, Level),
{200, [html],
#xmlel{name = <<"html">>,
attrs =
@@ -327,6 +332,7 @@ make_xhtml(Els, Host, Node, Lang, JID, Base) ->
[?XAE(<<"div">>, [{<<"id">>, <<"copyright">>}],
[?XE(<<"p">>,
[?AC(<<"https://www.ejabberd.im/">>, <<"ejabberd">>),
?C(<<" ">>), ?C(ejabberd_option:version()),
?C(<<" (c) 2002-2020 ">>),
?AC(<<"https://www.process-one.net/">>, <<"ProcessOne, leader in messaging and push solutions">>)]
)])])])]}}.
@@ -334,19 +340,19 @@ make_xhtml(Els, Host, Node, Lang, JID, Base) ->
direction(<<"he">>) -> [{<<"dir">>, <<"rtl">>}];
direction(_) -> [].
extract_base_path(Path, RPath) ->
Base = lists:sublist(Path, length(Path)-length(RPath)),
iolist_to_binary("/" ++ lists:join("/", Base) ++ "/").
get_base_path(Host, Node, Level) ->
SumHost = case Host of
global -> 0;
_ -> -2
end,
SumNode = case Node of
cluster -> 0;
_ -> -2
end,
get_base_path_sum(SumHost, SumNode, Level).
get_base_path(global, cluster, Base) -> Base;
get_base_path(Host, cluster, Base) ->
<<Base/binary, "/server/", Host/binary, "/">>;
get_base_path(global, Node, Base) ->
<<Base/binary, "/node/",
(iolist_to_binary(atom_to_list(Node)))/binary, "/">>;
get_base_path(Host, Node, Base) ->
<<Base/binary, "/server/", Host/binary, "/node/",
(iolist_to_binary(atom_to_list(Node)))/binary, "/">>.
get_base_path_sum(SumHost, SumNode, Level) ->
iolist_to_binary(lists:duplicate(Level + SumHost + SumNode, "../")).
%%%==================================
%%%% css & images
@@ -357,11 +363,11 @@ additions_js() ->
{error, _} -> <<>>
end.
css(Base, Host) ->
css(Host) ->
case misc:read_css("admin.css") of
{ok, CSS} ->
BP = get_base_path(Host, cluster, Base),
re:replace(CSS, <<"@BASE@">>, BP, [{return, binary}]);
Base = get_base_path(Host, cluster, 0),
re:replace(CSS, <<"@BASE@">>, Base, [{return, binary}]);
{error, _} ->
<<>>
end.
@@ -387,73 +393,73 @@ logo_fill() ->
%%%==================================
%%%% process_admin
process_admin(Base, global, #request{path = [], lang = Lang}, AJID) ->
process_admin(global, #request{path = [], lang = Lang}, AJID) ->
make_xhtml((?H1GL((translate:translate(Lang, ?T("Administration"))), <<"">>,
<<"Contents">>))
++
[?XE(<<"ul">>,
[?LI([?ACT(MIU, MIN)])
|| {MIU, MIN}
<- get_menu_items(global, cluster, Lang, AJID, Base)])],
global, Lang, AJID, Base);
process_admin(Base, Host, #request{path = [], lang = Lang}, AJID) ->
<- get_menu_items(global, cluster, Lang, AJID, 0)])],
global, Lang, AJID, 0);
process_admin(Host, #request{path = [], lang = Lang}, AJID) ->
make_xhtml([?XCT(<<"h1">>, ?T("Administration")),
?XE(<<"ul">>,
[?LI([?ACT(MIU, MIN)])
|| {MIU, MIN}
<- get_menu_items(Host, cluster, Lang, AJID, Base)])],
Host, Lang, AJID, Base);
process_admin(Base, Host, #request{path = [<<"style.css">>]}, _) ->
<- get_menu_items(Host, cluster, Lang, AJID, 2)])],
Host, Lang, AJID, 2);
process_admin(Host, #request{path = [<<"style.css">>]}, _) ->
{200,
[{<<"Content-Type">>, <<"text/css">>}, last_modified(),
cache_control_public()],
css(Base, Host)};
process_admin(_Base, _Host, #request{path = [<<"favicon.ico">>]}, _) ->
css(Host)};
process_admin(_Host, #request{path = [<<"favicon.ico">>]}, _) ->
{200,
[{<<"Content-Type">>, <<"image/x-icon">>},
last_modified(), cache_control_public()],
favicon()};
process_admin(_Base, _Host, #request{path = [<<"logo.png">>]}, _) ->
process_admin(_Host, #request{path = [<<"logo.png">>]}, _) ->
{200,
[{<<"Content-Type">>, <<"image/png">>}, last_modified(),
cache_control_public()],
logo()};
process_admin(_Base, _Host, #request{path = [<<"logo-fill.png">>]}, _) ->
process_admin(_Host, #request{path = [<<"logo-fill.png">>]}, _) ->
{200,
[{<<"Content-Type">>, <<"image/png">>}, last_modified(),
cache_control_public()],
logo_fill()};
process_admin(_Base, _Host, #request{path = [<<"additions.js">>]}, _) ->
process_admin(_Host, #request{path = [<<"additions.js">>]}, _) ->
{200,
[{<<"Content-Type">>, <<"text/javascript">>},
last_modified(), cache_control_public()],
additions_js()};
process_admin(Base, global, #request{path = [<<"vhosts">>], lang = Lang}, AJID) ->
process_admin(global, #request{path = [<<"vhosts">>], lang = Lang}, AJID) ->
Res = list_vhosts(Lang, AJID),
make_xhtml((?H1GL((translate:translate(Lang, ?T("Virtual Hosts"))),
<<"virtual-hosting">>, ?T("Virtual Hosting")))
<<"basic/#xmpp-domains">>, ?T("XMPP Domains")))
++ Res,
global, Lang, AJID, Base);
process_admin(Base, Host, #request{path = [<<"users">>], q = Query,
global, Lang, AJID, 1);
process_admin(Host, #request{path = [<<"users">>], q = Query,
lang = Lang}, AJID)
when is_binary(Host) ->
Res = list_users(Base, Host, Query, Lang, fun url_func/1),
Res = list_users(Host, Query, Lang, fun url_func/1),
make_xhtml([?XCT(<<"h1">>, ?T("Users"))] ++ Res, Host,
Lang, AJID, Base);
process_admin(Base, Host, #request{path = [<<"users">>, Diap],
Lang, AJID, 3);
process_admin(Host, #request{path = [<<"users">>, Diap],
lang = Lang}, AJID)
when is_binary(Host) ->
Res = list_users_in_diapason(Base, Host, Diap, Lang,
Res = list_users_in_diapason(Host, Diap, Lang,
fun url_func/1),
make_xhtml([?XCT(<<"h1">>, ?T("Users"))] ++ Res, Host,
Lang, AJID, Base);
process_admin(Base, Host, #request{path = [<<"online-users">>],
Lang, AJID, 4);
process_admin(Host, #request{path = [<<"online-users">>],
lang = Lang}, AJID)
when is_binary(Host) ->
Res = list_online_users(Host, Lang),
make_xhtml([?XCT(<<"h1">>, ?T("Online Users"))] ++ Res,
Host, Lang, AJID, Base);
process_admin(Base, Host, #request{path = [<<"last-activity">>],
Host, Lang, AJID, 3);
process_admin(Host, #request{path = [<<"last-activity">>],
q = Query, lang = Lang}, AJID)
when is_binary(Host) ->
?DEBUG("Query: ~p", [Query]),
@@ -466,7 +472,7 @@ process_admin(Base, Host, #request{path = [<<"last-activity">>],
list_last_activity(Host, Lang, false, Month);
_ -> list_last_activity(Host, Lang, true, Month)
end,
PageH1 = ?H1GL(translate:translate(Lang, ?T("Users Last Activity")), <<"mod-last">>, <<"mod_last">>),
PageH1 = ?H1GL(translate:translate(Lang, ?T("Users Last Activity")), <<"modules/#mod-last">>, <<"mod_last">>),
make_xhtml(PageH1 ++
[?XAE(<<"form">>,
[{<<"action">>, <<"">>}, {<<"method">>, <<"post">>}],
@@ -494,37 +500,49 @@ process_admin(Base, Host, #request{path = [<<"last-activity">>],
?INPUTT(<<"submit">>, <<"integral">>,
?T("Show Integral Table"))])]
++ Res,
Host, Lang, AJID, Base);
process_admin(Base, Host, #request{path = [<<"stats">>], lang = Lang}, AJID) ->
Host, Lang, AJID, 3);
process_admin(Host, #request{path = [<<"stats">>], lang = Lang}, AJID) ->
Res = get_stats(Host, Lang),
PageH1 = ?H1GL(translate:translate(Lang, ?T("Statistics")), <<"mod-stats">>, <<"mod_stats">>),
make_xhtml(PageH1 ++ Res, Host, Lang, AJID, Base);
process_admin(Base, Host, #request{path = [<<"user">>, U],
PageH1 = ?H1GL(translate:translate(Lang, ?T("Statistics")), <<"modules/#mod-stats">>, <<"mod_stats">>),
Level = case Host of
global -> 1;
_ -> 3
end,
make_xhtml(PageH1 ++ Res, Host, Lang, AJID, Level);
process_admin(Host, #request{path = [<<"user">>, U],
q = Query, lang = Lang}, AJID) ->
case ejabberd_auth:user_exists(U, Host) of
true ->
Res = user_info(U, Host, Query, Lang),
make_xhtml(Res, Host, Lang, AJID, Base);
make_xhtml(Res, Host, Lang, AJID, 4);
false ->
make_xhtml([?XCT(<<"h1">>, ?T("Not Found"))], Host,
Lang, AJID, Base)
Lang, AJID, 4)
end;
process_admin(Base, Host, #request{path = [<<"nodes">>], lang = Lang}, AJID) ->
process_admin(Host, #request{path = [<<"nodes">>], lang = Lang}, AJID) ->
Res = get_nodes(Lang),
make_xhtml(Res, Host, Lang, AJID, Base);
process_admin(Base, Host, #request{path = [<<"node">>, SNode | NPath],
Level = case Host of
global -> 1;
_ -> 3
end,
make_xhtml(Res, Host, Lang, AJID, Level);
process_admin(Host, #request{path = [<<"node">>, SNode | NPath],
q = Query, lang = Lang}, AJID) ->
case search_running_node(SNode) of
false ->
make_xhtml([?XCT(<<"h1">>, ?T("Node not found"))], Host,
Lang, AJID, Base);
Lang, AJID, 2);
Node ->
Res = get_node(Base, Host, Node, NPath, Query, Lang),
make_xhtml(Res, Host, Node, Lang, AJID, Base)
Res = get_node(Host, Node, NPath, Query, Lang),
Level = case Host of
global -> 2 + length(NPath);
_ -> 4 + length(NPath)
end,
make_xhtml(Res, Host, Node, Lang, AJID, Level)
end;
%%%==================================
%%%% process_admin default case
process_admin(Base, Host, #request{lang = Lang} = Request, AJID) ->
process_admin(Host, #request{lang = Lang} = Request, AJID) ->
Res = case Host of
global ->
ejabberd_hooks:run_fold(
@@ -533,13 +551,17 @@ process_admin(Base, Host, #request{lang = Lang} = Request, AJID) ->
ejabberd_hooks:run_fold(
webadmin_page_host, Host, [], [Host, Request])
end,
Level = case Host of
global -> length(Request#request.path);
_ -> 2 + length(Request#request.path)
end,
case Res of
[] ->
setelement(1,
make_xhtml([?XC(<<"h1">>, <<"Not Found">>)], Host, Lang,
AJID, Base),
AJID, Level),
404);
_ -> make_xhtml(Res, Host, Lang, AJID, Base)
_ -> make_xhtml(Res, Host, Lang, AJID, Level)
end.
term_to_id(T) -> base64:encode((term_to_binary(T))).
@@ -586,13 +608,13 @@ list_vhosts2(Lang, Hosts) ->
%%%==================================
%%%% list_users
list_users(Base, Host, Query, Lang, URLFunc) ->
list_users(Host, Query, Lang, URLFunc) ->
Res = list_users_parse_query(Query, Host),
Users = ejabberd_auth:get_users(Host),
SUsers = lists:sort([{S, U} || {U, S} <- Users]),
FUsers = case length(SUsers) of
N when N =< 100 ->
[list_given_users(Host, SUsers, Base, Lang,
[list_given_users(Host, SUsers, <<"../">>, Lang,
URLFunc)];
N ->
NParts = trunc(math:sqrt(N * 6.17999999999999993783e-1))
@@ -668,18 +690,17 @@ list_users_parse_query(Query, Host) ->
false -> nothing
end.
list_users_in_diapason(Base, Host, Diap, Lang, URLFunc) ->
list_users_in_diapason(Host, Diap, Lang, URLFunc) ->
Users = ejabberd_auth:get_users(Host),
SUsers = lists:sort([{S, U} || {U, S} <- Users]),
[S1, S2] = ejabberd_regexp:split(Diap, <<"-">>),
N1 = binary_to_integer(S1),
N2 = binary_to_integer(S2),
Sub = lists:sublist(SUsers, N1, N2 - N1 + 1),
[list_given_users(Host, Sub, Base, Lang,
[list_given_users(Host, Sub, <<"../../">>, Lang,
URLFunc)].
list_given_users(Host, Users, Base, Lang, URLFunc) ->
Prefix = get_base_path(Host, cluster, Base),
list_given_users(Host, Users, Prefix, Lang, URLFunc) ->
ModOffline = get_offlinemsg_module(Host),
?XE(<<"table">>,
[?XE(<<"thead">>,
@@ -909,7 +930,7 @@ user_info(User, Server, Query, Lang) ->
end;
_ -> translate:translate(Lang, ?T("Online"))
end,
[?XC(<<"h1">>, (str:format(translate:translate(Lang, ?T("User ~ts")),
[?XC(<<"h1">>, (str:translate_and_format(Lang, ?T("User ~ts"),
[us_to_list(US)])))]
++
case Res of
@@ -928,7 +949,7 @@ user_info(User, Server, Query, Lang) ->
[?C(LastActivity)] ++
UserItems ++
[?P,
?INPUTT(<<"submit">>, <<"removeuser">>,
?INPUTTD(<<"submit">>, <<"removeuser">>,
?T("Remove User"))]))].
user_parse_query(User, Server, Query) ->
@@ -1061,12 +1082,12 @@ search_running_node(SNode, [Node | Nodes]) ->
_ -> search_running_node(SNode, Nodes)
end.
get_node(Base, global, Node, [], Query, Lang) ->
get_node(global, Node, [], Query, Lang) ->
Res = node_parse_query(Node, Query),
BP = get_base_path(global, Node, Base),
MenuItems2 = make_menu_items(global, Node, BP, Lang),
Base = get_base_path(global, Node, 2),
MenuItems2 = make_menu_items(global, Node, Base, Lang),
[?XC(<<"h1">>,
(str:format(translate:translate(Lang, ?T("Node ~p")), [Node])))]
(str:translate_and_format(Lang, ?T("Node ~p"), [Node])))]
++
case Res of
ok -> [?XREST(?T("Submitted"))];
@@ -1084,13 +1105,13 @@ get_node(Base, global, Node, [], Query, Lang) ->
[{<<"action">>, <<"">>}, {<<"method">>, <<"post">>}],
[?INPUTT(<<"submit">>, <<"restart">>, ?T("Restart")),
?C(<<" ">>),
?INPUTT(<<"submit">>, <<"stop">>, ?T("Stop"))])];
get_node(Base, Host, Node, [], _Query, Lang) ->
BP = get_base_path(Host, Node, Base),
MenuItems2 = make_menu_items(Host, Node, BP, Lang),
[?XC(<<"h1">>, (str:format(translate:translate(Lang, ?T("Node ~p")), [Node]))),
?INPUTTD(<<"submit">>, <<"stop">>, ?T("Stop"))])];
get_node(Host, Node, [], _Query, Lang) ->
Base = get_base_path(Host, Node, 4),
MenuItems2 = make_menu_items(Host, Node, Base, Lang),
[?XC(<<"h1">>, (str:translate_and_format(Lang, ?T("Node ~p"), [Node]))),
?XE(<<"ul">>, MenuItems2)];
get_node(_Base, global, Node, [<<"db">>], Query, Lang) ->
get_node(global, Node, [<<"db">>], Query, Lang) ->
case ejabberd_cluster:call(Node, mnesia, system_info, [tables]) of
{badrpc, _Reason} ->
[?XCT(<<"h1">>, ?T("RPC Call Error"))];
@@ -1144,7 +1165,7 @@ get_node(_Base, global, Node, [<<"db">>], Query, Lang) ->
end,
STables),
[?XC(<<"h1">>,
(str:format(translate:translate(Lang, ?T("Database Tables at ~p")),
(str:translate_and_format(Lang, ?T("Database Tables at ~p"),
[Node]))
)]
++
@@ -1168,7 +1189,7 @@ get_node(_Base, global, Node, [<<"db">>], Query, Lang) ->
<<"submit">>,
?T("Submit"))])])]))])])]
end;
get_node(_Base, global, Node, [<<"backup">>], Query, Lang) ->
get_node(global, Node, [<<"backup">>], Query, Lang) ->
HomeDirRaw = case {os:getenv("HOME"), os:type()} of
{EnvHome, _} when is_list(EnvHome) -> list_to_binary(EnvHome);
{false, {win32, _Osname}} -> <<"C:/">>;
@@ -1182,7 +1203,7 @@ get_node(_Base, global, Node, [<<"backup">>], Query, Lang) ->
[?XRES(<<(translate:translate(Lang, ?T("Error")))/binary, ": ",
((str:format("~p", [Error])))/binary>>)]
end,
[?XC(<<"h1">>, (str:format(translate:translate(Lang, ?T("Backup of ~p")), [Node])))]
[?XC(<<"h1">>, (str:translate_and_format(Lang, ?T("Backup of ~p"), [Node])))]
++
ResS ++
[?XCT(<<"p">>,
@@ -1318,7 +1339,7 @@ get_node(_Base, global, Node, [<<"backup">>], Query, Lang) ->
?XE(<<"td">>,
[?INPUTT(<<"submit">>, <<"import_dir">>,
?T("OK"))])])])])])];
get_node(_Base, global, Node, [<<"stats">>], _Query, Lang) ->
get_node(global, Node, [<<"stats">>], _Query, Lang) ->
UpTime = ejabberd_cluster:call(Node, erlang, statistics,
[wall_clock]),
UpTimeS = (str:format("~.3f",
@@ -1336,7 +1357,7 @@ get_node(_Base, global, Node, [<<"stats">>], _Query, Lang) ->
TransactionsLogged = ejabberd_cluster:call(Node, mnesia, system_info,
[transaction_log_writes]),
[?XC(<<"h1">>,
(str:format(translate:translate(Lang, ?T("Statistics of ~p")), [Node]))),
(str:translate_and_format(Lang, ?T("Statistics of ~p"), [Node]))),
?XAE(<<"table">>, [],
[?XE(<<"tbody">>,
[?XE(<<"tr">>,
@@ -1367,7 +1388,7 @@ get_node(_Base, global, Node, [<<"stats">>], _Query, Lang) ->
[?XCT(<<"td">>, ?T("Transactions Logged:")),
?XAC(<<"td">>, [{<<"class">>, <<"alignright">>}],
(pretty_string_int(TransactionsLogged)))])])])];
get_node(_Base, global, Node, [<<"update">>], Query, Lang) ->
get_node(global, Node, [<<"update">>], Query, Lang) ->
ejabberd_cluster:call(Node, code, purge, [ejabberd_update]),
Res = node_update_parse_query(Node, Query),
ejabberd_cluster:call(Node, code, load_file, [ejabberd_update]),
@@ -1404,7 +1425,7 @@ get_node(_Base, global, Node, [<<"update">>], Query, Lang) ->
FmtLowLevelScript = (?XC(<<"pre">>,
(str:format("~p", [LowLevelScript])))),
[?XC(<<"h1">>,
(str:format(translate:translate(Lang, ?T("Update ~p")), [Node])))]
(str:translate_and_format(Lang, ?T("Update ~p"), [Node])))]
++
case Res of
ok -> [?XREST(?T("Submitted"))];
@@ -1423,7 +1444,7 @@ get_node(_Base, global, Node, [<<"update">>], Query, Lang) ->
?XC(<<"pre">>, (misc:atom_to_binary(Check))),
?BR,
?INPUTT(<<"submit">>, <<"update">>, ?T("Update"))])];
get_node(_Base, Host, Node, NPath, Query, Lang) ->
get_node(Host, Node, NPath, Query, Lang) ->
Res = case Host of
global ->
ejabberd_hooks:run_fold(webadmin_page_node, Host, [],
@@ -1714,12 +1735,12 @@ pretty_string_int(String) when is_binary(String) ->
%%%==================================
%%%% navigation menu
%% @spec (Host, Node, Lang, JID::jid()) -> [LI]
%% @spec (Host, Node, Lang, JID::jid(), Level::integer()) -> [LI]
make_navigation(Host, Node, Lang, JID, Level) ->
Menu = make_navigation_menu(Host, Node, Lang, JID, Level),
make_menu_items(Lang, Menu).
%% @spec (Host, Node, Lang, JID::jid()) -> Menu
%% @spec (Host, Node, Lang, JID::jid(), Level::integer()) -> Menu
%% where Host = global | string()
%% Node = cluster | string()
%% Lang = string()
@@ -1735,19 +1756,19 @@ make_navigation_menu(Host, Node, Lang, JID, Level) ->
make_server_menu(HostMenu, NodeMenu, Lang, JID, Level).
%% @spec (Host, Node, Base, Lang) -> [LI]
make_menu_items(global, cluster, BP, Lang) ->
make_menu_items(global, cluster, Base, Lang) ->
HookItems = get_menu_items_hook(server, Lang),
make_menu_items(Lang, {BP, <<"">>, HookItems});
make_menu_items(global, Node, BP, Lang) ->
make_menu_items(Lang, {Base, <<"">>, HookItems});
make_menu_items(global, Node, Base, Lang) ->
HookItems = get_menu_items_hook({node, Node}, Lang),
make_menu_items(Lang, {BP, <<"">>, HookItems});
make_menu_items(Host, cluster, BP, Lang) ->
make_menu_items(Lang, {Base, <<"">>, HookItems});
make_menu_items(Host, cluster, Base, Lang) ->
HookItems = get_menu_items_hook({host, Host}, Lang),
make_menu_items(Lang, {BP, <<"">>, HookItems});
make_menu_items(Host, Node, BP, Lang) ->
make_menu_items(Lang, {Base, <<"">>, HookItems});
make_menu_items(Host, Node, Base, Lang) ->
HookItems = get_menu_items_hook({hostnode, Host, Node},
Lang),
make_menu_items(Lang, {BP, <<"">>, HookItems}).
make_menu_items(Lang, {Base, <<"">>, HookItems}).
make_host_node_menu(global, _, _Lang, _JID, _Level) ->
{<<"">>, <<"">>, []};
@@ -1756,10 +1777,9 @@ make_host_node_menu(_, cluster, _Lang, _JID, _Level) ->
make_host_node_menu(Host, Node, Lang, JID, Level) ->
HostNodeBase = get_base_path(Host, Node, Level),
HostNodeFixed = get_menu_items_hook({hostnode, Host, Node}, Lang),
HostNodeBasePath = url_to_path(HostNodeBase),
HostNodeFixed2 = [Tuple
|| Tuple <- HostNodeFixed,
is_allowed_path(HostNodeBasePath, Tuple, JID)],
is_allowed_path(Host, Tuple, JID)],
{HostNodeBase, iolist_to_binary(atom_to_list(Node)),
HostNodeFixed2}.
@@ -1774,10 +1794,9 @@ make_host_menu(Host, HostNodeMenu, Lang, JID, Level) ->
[{<<"nodes">>, ?T("Nodes"), HostNodeMenu},
{<<"stats">>, ?T("Statistics")}]
++ get_menu_items_hook({host, Host}, Lang),
HostBasePath = url_to_path(HostBase),
HostFixed2 = [Tuple
|| Tuple <- HostFixed,
is_allowed_path(HostBasePath, Tuple, JID)],
is_allowed_path(Host, Tuple, JID)],
{HostBase, Host, HostFixed2}.
make_node_menu(_Host, cluster, _Lang, _Level) ->
@@ -1789,19 +1808,21 @@ make_node_menu(global, Node, Lang, Level) ->
{<<"stats">>, ?T("Statistics")},
{<<"update">>, ?T("Update")}]
++ get_menu_items_hook({node, Node}, Lang),
{NodeBase, iolist_to_binary(atom_to_list(Node)), NodeFixed}.
{NodeBase, iolist_to_binary(atom_to_list(Node)),
NodeFixed};
make_node_menu(_Host, _Node, _Lang, _Level) ->
{<<"">>, <<"">>, []}.
make_server_menu(HostMenu, NodeMenu, Lang, JID, Level) ->
BP = get_base_path(global, cluster, Level),
Base = get_base_path(global, cluster, Level),
Fixed = [{<<"vhosts">>, ?T("Virtual Hosts"), HostMenu},
{<<"nodes">>, ?T("Nodes"), NodeMenu},
{<<"stats">>, ?T("Statistics")}]
++ get_menu_items_hook(server, Lang),
Base = url_to_path(BP),
Fixed2 = [Tuple
|| Tuple <- Fixed,
is_allowed_path(Base, Tuple, JID)],
{BP, <<"">>, Fixed2}.
is_allowed_path(global, Tuple, JID)],
{Base, <<"">>, Fixed2}.
get_menu_items_hook({hostnode, Host, Node}, Lang) ->
ejabberd_hooks:run_fold(webadmin_menu_hostnode, Host,
+11 -1
View File
@@ -45,7 +45,7 @@
-include("logger.hrl").
-include("xmpp.hrl").
-include_lib("xmpp/include/xmpp.hrl").
-include("ejabberd_http.hrl").
@@ -225,6 +225,16 @@ ws_loop(FrameInfo, Socket, WsHandleLoopPid, SocketMode, Shaper) ->
end,
erlang:demonitor(Ref),
websocket_close(Socket, WsHandleLoopPid, SocketMode, Code);
{text_with_reply, Data, Sender} ->
SocketMode:send(Socket, encode_frame(Data, 1)),
Sender ! {text_reply, self()},
ws_loop(FrameInfo, Socket, WsHandleLoopPid,
SocketMode, Shaper);
{data_with_reply, Data, Sender} ->
SocketMode:send(Socket, encode_frame(Data, 2)),
Sender ! {data_reply, self()},
ws_loop(FrameInfo, Socket, WsHandleLoopPid,
SocketMode, Shaper);
{text, Data} ->
SocketMode:send(Socket, encode_frame(Data, 1)),
ws_loop(FrameInfo, Socket, WsHandleLoopPid,

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