mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-24 16:23:40 +01:00
Change configuration file format to YAML
This commit is contained in:
parent
f68dfacbbf
commit
91a74e3e27
12
Makefile.in
12
Makefile.in
@ -109,9 +109,9 @@ install: all
|
||||
#
|
||||
# Configuration files
|
||||
$(INSTALL) -d -m 750 $(G_USER) $(ETCDIR)
|
||||
[ -f $(ETCDIR)/ejabberd.cfg ] \
|
||||
&& $(INSTALL) -b -m 640 $(G_USER) ejabberd.cfg.example $(ETCDIR)/ejabberd.cfg-new \
|
||||
|| $(INSTALL) -b -m 640 $(G_USER) ejabberd.cfg.example $(ETCDIR)/ejabberd.cfg
|
||||
[ -f $(ETCDIR)/ejabberd.yml ] \
|
||||
&& $(INSTALL) -b -m 640 $(G_USER) ejabberd.yml.example $(ETCDIR)/ejabberd.yml-new \
|
||||
|| $(INSTALL) -b -m 640 $(G_USER) ejabberd.yml.example $(ETCDIR)/ejabberd.yml
|
||||
$(SED) -e "s*{{rootdir}}*@prefix@*" \
|
||||
-e "s*{{installuser}}*@INSTALLUSER@*" \
|
||||
-e "s*{{libdir}}*@libdir@*" \
|
||||
@ -120,9 +120,9 @@ install: all
|
||||
-e "s*{{docdir}}*@docdir@*" \
|
||||
-e "s*{{erl}}*@ERL@*" ejabberdctl.template \
|
||||
> ejabberdctl.example
|
||||
[ -f $(ETCDIR)/ejabberdctl.cfg ] \
|
||||
&& $(INSTALL) -b -m 640 $(G_USER) ejabberdctl.cfg.example $(ETCDIR)/ejabberdctl.cfg-new \
|
||||
|| $(INSTALL) -b -m 640 $(G_USER) ejabberdctl.cfg.example $(ETCDIR)/ejabberdctl.cfg
|
||||
[ -f $(ETCDIR)/ejabberdctl.yml ] \
|
||||
&& $(INSTALL) -b -m 640 $(G_USER) ejabberdctl.yml.example $(ETCDIR)/ejabberdctl.yml-new \
|
||||
|| $(INSTALL) -b -m 640 $(G_USER) ejabberdctl.yml.example $(ETCDIR)/ejabberdctl.yml
|
||||
$(INSTALL) -b -m 644 $(G_USER) inetrc $(ETCDIR)/inetrc
|
||||
#
|
||||
# Administration script
|
||||
|
1
README
1
README
@ -9,6 +9,7 @@ To compile ejabberd you need:
|
||||
- GNU Make
|
||||
- GCC
|
||||
- Libexpat 1.95 or higher
|
||||
- Libyaml 1.4 or higher
|
||||
- Erlang/OTP R15B or higher.
|
||||
- OpenSSL 0.9.8 or higher, for STARTTLS, SASL and SSL encryption.
|
||||
- Zlib 1.2.3 or higher, for Stream Compression support
|
||||
|
2973
doc/guide.html
2973
doc/guide.html
File diff suppressed because it is too large
Load Diff
2693
doc/guide.tex
2693
doc/guide.tex
File diff suppressed because it is too large
Load Diff
@ -1,609 +0,0 @@
|
||||
%%%
|
||||
%%% ejabberd configuration file
|
||||
%%%
|
||||
%%%'
|
||||
|
||||
%%% The parameters used in this configuration file are explained in more detail
|
||||
%%% in the ejabberd Installation and Operation Guide.
|
||||
%%% Please consult the Guide in case of doubts, it is included with
|
||||
%%% your copy of ejabberd, and is also available online at
|
||||
%%% http://www.process-one.net/en/ejabberd/docs/
|
||||
|
||||
%%% This configuration file contains Erlang terms.
|
||||
%%% In case you want to understand the syntax, here are the concepts:
|
||||
%%%
|
||||
%%% - The character to comment a line is %
|
||||
%%%
|
||||
%%% - Each term ends in a dot, for example:
|
||||
%%% override_global.
|
||||
%%%
|
||||
%%% - A tuple has a fixed definition, its elements are
|
||||
%%% enclosed in {}, and separated with commas:
|
||||
%%% {loglevel, 4}.
|
||||
%%%
|
||||
%%% - A list can have as many elements as you want,
|
||||
%%% and is enclosed in [], for example:
|
||||
%%% [http_poll, web_admin, tls]
|
||||
%%%
|
||||
%%% - A keyword of ejabberd is a word in lowercase.
|
||||
%%% Strings are enclosed in "" and can contain spaces, dots, ...
|
||||
%%% {language, "en"}.
|
||||
%%% {ldap_rootdn, "dc=example,dc=com"}.
|
||||
%%%
|
||||
%%% - This term includes a tuple, a keyword, a list, and two strings:
|
||||
%%% {hosts, ["jabber.example.net", "im.example.com"]}.
|
||||
%%%
|
||||
|
||||
|
||||
%%%. =======================
|
||||
%%%' OVERRIDE STORED OPTIONS
|
||||
|
||||
%%
|
||||
%% Override the old values stored in the database.
|
||||
%%
|
||||
|
||||
%%
|
||||
%% Override global options (shared by all ejabberd nodes in a cluster).
|
||||
%%
|
||||
%%override_global.
|
||||
|
||||
%%
|
||||
%% Override local options (specific for this particular ejabberd node).
|
||||
%%
|
||||
%%override_local.
|
||||
|
||||
%%
|
||||
%% Remove the Access Control Lists before new ones are added.
|
||||
%%
|
||||
%%override_acls.
|
||||
|
||||
|
||||
%%%. =========
|
||||
%%%' DEBUGGING
|
||||
|
||||
%%
|
||||
%% loglevel: Verbosity of log files generated by ejabberd.
|
||||
%% 0: No ejabberd log at all (not recommended)
|
||||
%% 1: Critical
|
||||
%% 2: Error
|
||||
%% 3: Warning
|
||||
%% 4: Info
|
||||
%% 5: Debug
|
||||
%%
|
||||
{loglevel, 4}.
|
||||
|
||||
%%
|
||||
%% watchdog_admins: Only useful for developers: if an ejabberd process
|
||||
%% consumes a lot of memory, send live notifications to these XMPP
|
||||
%% accounts.
|
||||
%%
|
||||
%%{watchdog_admins, ["bob@example.com"]}.
|
||||
|
||||
|
||||
%%%. ================
|
||||
%%%' SERVED HOSTNAMES
|
||||
|
||||
%%
|
||||
%% hosts: Domains served by ejabberd.
|
||||
%% You can define one or several, for example:
|
||||
%% {hosts, ["example.net", "example.com", "example.org"]}.
|
||||
%%
|
||||
{hosts, ["localhost"]}.
|
||||
|
||||
%%
|
||||
%% route_subdomains: Delegate subdomains to other XMPP servers.
|
||||
%% For example, if this ejabberd serves example.org and you want
|
||||
%% to allow communication with an XMPP server called im.example.org.
|
||||
%%
|
||||
%%{route_subdomains, s2s}.
|
||||
|
||||
|
||||
%%%. ===============
|
||||
%%%' LISTENING PORTS
|
||||
|
||||
%%
|
||||
%% listen: The ports ejabberd will listen on, which service each is handled
|
||||
%% by and what options to start it with.
|
||||
%%
|
||||
{listen,
|
||||
[
|
||||
|
||||
{5222, ejabberd_c2s, [
|
||||
|
||||
%%
|
||||
%% If TLS is compiled in and you installed a SSL
|
||||
%% certificate, specify the full path to the
|
||||
%% file and uncomment this line:
|
||||
%%
|
||||
%%{certfile, "/path/to/ssl.pem"}, starttls,
|
||||
|
||||
{access, c2s},
|
||||
{shaper, c2s_shaper},
|
||||
{max_stanza_size, 65536}
|
||||
]},
|
||||
|
||||
%%
|
||||
%% To enable the old SSL connection method on port 5223:
|
||||
%%
|
||||
%%{5223, ejabberd_c2s, [
|
||||
%% {access, c2s},
|
||||
%% {shaper, c2s_shaper},
|
||||
%% {certfile, "/path/to/ssl.pem"}, tls,
|
||||
%% {max_stanza_size, 65536}
|
||||
%% ]},
|
||||
|
||||
{5269, ejabberd_s2s_in, [
|
||||
{shaper, s2s_shaper},
|
||||
{max_stanza_size, 131072}
|
||||
]},
|
||||
|
||||
%%
|
||||
%% ejabberd_service: Interact with external components (transports, ...)
|
||||
%%
|
||||
%%{8888, ejabberd_service, [
|
||||
%% {access, all},
|
||||
%% {shaper_rule, fast},
|
||||
%% {hosts, ["icq.example.org", "sms.example.org"],
|
||||
%% [{password, "secret"}]
|
||||
%% }
|
||||
%% ]},
|
||||
|
||||
%%
|
||||
%% ejabberd_stun: Handles STUN Binding requests
|
||||
%%
|
||||
%%{{3478, udp}, ejabberd_stun, []},
|
||||
|
||||
{5280, ejabberd_http, [
|
||||
%%{request_handlers,
|
||||
%% [
|
||||
%% {["pub", "archive"], mod_http_fileserver}
|
||||
%% ]},
|
||||
captcha,
|
||||
http_bind,
|
||||
http_poll,
|
||||
%%register,
|
||||
web_admin
|
||||
]}
|
||||
|
||||
]}.
|
||||
|
||||
%%
|
||||
%% s2s_use_starttls: Enable STARTTLS + Dialback for S2S connections.
|
||||
%% Allowed values are: false optional required required_trusted
|
||||
%% You must specify a certificate file.
|
||||
%%
|
||||
%%{s2s_use_starttls, optional}.
|
||||
|
||||
%%
|
||||
%% s2s_certfile: Specify a certificate file.
|
||||
%%
|
||||
%%{s2s_certfile, "/path/to/ssl.pem"}.
|
||||
|
||||
%%
|
||||
%% domain_certfile: Specify a different certificate for each served hostname.
|
||||
%%
|
||||
%%{domain_certfile, "example.org", "/path/to/example_org.pem"}.
|
||||
%%{domain_certfile, "example.com", "/path/to/example_com.pem"}.
|
||||
|
||||
%%
|
||||
%% S2S whitelist or blacklist
|
||||
%%
|
||||
%% Default s2s policy for undefined hosts.
|
||||
%%
|
||||
%%{s2s_default_policy, allow}.
|
||||
|
||||
%%
|
||||
%% Allow or deny communication with specific servers.
|
||||
%%
|
||||
%%{{s2s_host, "goodhost.org"}, allow}.
|
||||
%%{{s2s_host, "badhost.org"}, deny}.
|
||||
|
||||
%%
|
||||
%% Outgoing S2S options
|
||||
%%
|
||||
%% Preferred address families (which to try first) and connect timeout
|
||||
%% in milliseconds.
|
||||
%%
|
||||
%%{outgoing_s2s_options, [ipv4, ipv6], 10000}.
|
||||
|
||||
|
||||
%%%. ==============
|
||||
%%%' AUTHENTICATION
|
||||
|
||||
%%
|
||||
%% auth_method: Method used to authenticate the users.
|
||||
%% The default method is the internal.
|
||||
%% If you want to use a different method,
|
||||
%% comment this line and enable the correct ones.
|
||||
%%
|
||||
{auth_method, internal}.
|
||||
%%
|
||||
%% Store the plain passwords or hashed for SCRAM:
|
||||
%%{auth_password_format, plain}.
|
||||
%%{auth_password_format, scram}.
|
||||
%%
|
||||
%% Define the FQDN if ejabberd doesn't detect it:
|
||||
%%{fqdn, "server3.example.com"}.
|
||||
|
||||
%%
|
||||
%% Authentication using external script
|
||||
%% Make sure the script is executable by ejabberd.
|
||||
%%
|
||||
%%{auth_method, external}.
|
||||
%%{extauth_program, "/path/to/authentication/script"}.
|
||||
|
||||
%%
|
||||
%% Authentication using ODBC
|
||||
%% Remember to setup a database in the next section.
|
||||
%%
|
||||
%%{auth_method, odbc}.
|
||||
|
||||
%%
|
||||
%% Authentication using PAM
|
||||
%%
|
||||
%%{auth_method, pam}.
|
||||
%%{pam_service, "pamservicename"}.
|
||||
|
||||
%%
|
||||
%% Authentication using LDAP
|
||||
%%
|
||||
%%{auth_method, ldap}.
|
||||
%%
|
||||
%% List of LDAP servers:
|
||||
%%{ldap_servers, ["localhost"]}.
|
||||
%%
|
||||
%% Encryption of connection to LDAP servers:
|
||||
%%{ldap_encrypt, none}.
|
||||
%%{ldap_encrypt, tls}.
|
||||
%%
|
||||
%% Port to connect to on LDAP servers:
|
||||
%%{ldap_port, 389}.
|
||||
%%{ldap_port, 636}.
|
||||
%%
|
||||
%% LDAP manager:
|
||||
%%{ldap_rootdn, "dc=example,dc=com"}.
|
||||
%%
|
||||
%% Password of LDAP manager:
|
||||
%%{ldap_password, "******"}.
|
||||
%%
|
||||
%% Search base of LDAP directory:
|
||||
%%{ldap_base, "dc=example,dc=com"}.
|
||||
%%
|
||||
%% LDAP attribute that holds user ID:
|
||||
%%{ldap_uids, [{"mail", "%u@mail.example.org"}]}.
|
||||
%%
|
||||
%% LDAP filter:
|
||||
%%{ldap_filter, "(objectClass=shadowAccount)"}.
|
||||
|
||||
%%
|
||||
%% Anonymous login support:
|
||||
%% auth_method: anonymous
|
||||
%% anonymous_protocol: sasl_anon | login_anon | both
|
||||
%% allow_multiple_connections: true | false
|
||||
%%
|
||||
%%{host_config, "public.example.org", [{auth_method, anonymous},
|
||||
%% {allow_multiple_connections, false},
|
||||
%% {anonymous_protocol, sasl_anon}]}.
|
||||
%%
|
||||
%% To use both anonymous and internal authentication:
|
||||
%%
|
||||
%%{host_config, "public.example.org", [{auth_method, [internal, anonymous]}]}.
|
||||
|
||||
|
||||
%%%. ==============
|
||||
%%%' DATABASE SETUP
|
||||
|
||||
%% ejabberd by default uses the internal Mnesia database,
|
||||
%% so you do not necessarily need this section.
|
||||
%% This section provides configuration examples in case
|
||||
%% you want to use other database backends.
|
||||
%% Please consult the ejabberd Guide for details on database creation.
|
||||
|
||||
%%
|
||||
%% MySQL server:
|
||||
%%
|
||||
%%{odbc_server, {mysql, "server", "database", "username", "password"}}.
|
||||
%%
|
||||
%% If you want to specify the port:
|
||||
%%{odbc_server, {mysql, "server", 1234, "database", "username", "password"}}.
|
||||
|
||||
%%
|
||||
%% PostgreSQL server:
|
||||
%%
|
||||
%%{odbc_server, {pgsql, "server", "database", "username", "password"}}.
|
||||
%%
|
||||
%% If you want to specify the port:
|
||||
%%{odbc_server, {pgsql, "server", 1234, "database", "username", "password"}}.
|
||||
%%
|
||||
%% If you use PostgreSQL, have a large database, and need a
|
||||
%% faster but inexact replacement for "select count(*) from users"
|
||||
%%
|
||||
%%{pgsql_users_number_estimate, true}.
|
||||
|
||||
%%
|
||||
%% ODBC compatible or MSSQL server:
|
||||
%%
|
||||
%%{odbc_server, "DSN=ejabberd;UID=ejabberd;PWD=ejabberd"}.
|
||||
|
||||
%%
|
||||
%% Number of connections to open to the database for each virtual host
|
||||
%%
|
||||
%%{odbc_pool_size, 10}.
|
||||
|
||||
%%
|
||||
%% Interval to make a dummy SQL request to keep the connections to the
|
||||
%% database alive. Specify in seconds: for example 28800 means 8 hours
|
||||
%%
|
||||
%%{odbc_keepalive_interval, undefined}.
|
||||
|
||||
|
||||
%%%. ===============
|
||||
%%%' TRAFFIC SHAPERS
|
||||
|
||||
%%
|
||||
%% The "normal" shaper limits traffic speed to 1000 B/s
|
||||
%%
|
||||
{shaper, normal, {maxrate, 1000}}.
|
||||
|
||||
%%
|
||||
%% The "fast" shaper limits traffic speed to 50000 B/s
|
||||
%%
|
||||
{shaper, fast, {maxrate, 50000}}.
|
||||
|
||||
%%
|
||||
%% This option specifies the maximum number of elements in the queue
|
||||
%% of the FSM. Refer to the documentation for details.
|
||||
%%
|
||||
{max_fsm_queue, 1000}.
|
||||
|
||||
|
||||
%%%. ====================
|
||||
%%%' ACCESS CONTROL LISTS
|
||||
|
||||
%%
|
||||
%% The 'admin' ACL grants administrative privileges to XMPP accounts.
|
||||
%% You can put here as many accounts as you want.
|
||||
%%
|
||||
%%{acl, admin, {user, "aleksey", "localhost"}}.
|
||||
%%{acl, admin, {user, "ermine", "example.org"}}.
|
||||
|
||||
%%
|
||||
%% Blocked users
|
||||
%%
|
||||
%%{acl, blocked, {user, "baduser", "example.org"}}.
|
||||
%%{acl, blocked, {user, "test"}}.
|
||||
|
||||
%%
|
||||
%% Local users: don't modify this line.
|
||||
%%
|
||||
{acl, local, {user_regexp, ""}}.
|
||||
|
||||
%%
|
||||
%% More examples of ACLs
|
||||
%%
|
||||
%%{acl, jabberorg, {server, "jabber.org"}}.
|
||||
%%{acl, aleksey, {user, "aleksey", "jabber.ru"}}.
|
||||
%%{acl, test, {user_regexp, "^test"}}.
|
||||
%%{acl, test, {user_glob, "test*"}}.
|
||||
|
||||
%%
|
||||
%% Define specific ACLs in a virtual host.
|
||||
%%
|
||||
%%{host_config, "localhost",
|
||||
%% [
|
||||
%% {acl, admin, {user, "bob-local", "localhost"}}
|
||||
%% ]
|
||||
%%}.
|
||||
|
||||
|
||||
%%%. ============
|
||||
%%%' ACCESS RULES
|
||||
|
||||
%% Maximum number of simultaneous sessions allowed for a single user:
|
||||
{access, max_user_sessions, [{10, all}]}.
|
||||
|
||||
%% Maximum number of offline messages that users can have:
|
||||
{access, max_user_offline_messages, [{5000, admin}, {100, all}]}.
|
||||
|
||||
%% This rule allows access only for local users:
|
||||
{access, local, [{allow, local}]}.
|
||||
|
||||
%% Only non-blocked users can use c2s connections:
|
||||
{access, c2s, [{deny, blocked},
|
||||
{allow, all}]}.
|
||||
|
||||
%% For C2S connections, all users except admins use the "normal" shaper
|
||||
{access, c2s_shaper, [{none, admin},
|
||||
{normal, all}]}.
|
||||
|
||||
%% All S2S connections use the "fast" shaper
|
||||
{access, s2s_shaper, [{fast, all}]}.
|
||||
|
||||
%% Only admins can send announcement messages:
|
||||
{access, announce, [{allow, admin}]}.
|
||||
|
||||
%% Only admins can use the configuration interface:
|
||||
{access, configure, [{allow, admin}]}.
|
||||
|
||||
%% Admins of this server are also admins of the MUC service:
|
||||
{access, muc_admin, [{allow, admin}]}.
|
||||
|
||||
%% Only accounts of the local ejabberd server can create rooms:
|
||||
{access, muc_create, [{allow, local}]}.
|
||||
|
||||
%% All users are allowed to use the MUC service:
|
||||
{access, muc, [{allow, all}]}.
|
||||
|
||||
%% Only accounts on the local ejabberd server can create Pubsub nodes:
|
||||
{access, pubsub_createnode, [{allow, local}]}.
|
||||
|
||||
%% In-band registration allows registration of any possible username.
|
||||
%% To disable in-band registration, replace 'allow' with 'deny'.
|
||||
{access, register, [{allow, all}]}.
|
||||
|
||||
%% By default the frequency of account registrations from the same IP
|
||||
%% is limited to 1 account every 10 minutes. To disable, specify: infinity
|
||||
%%{registration_timeout, 600}.
|
||||
|
||||
%%
|
||||
%% Define specific Access Rules in a virtual host.
|
||||
%%
|
||||
%%{host_config, "localhost",
|
||||
%% [
|
||||
%% {access, c2s, [{allow, admin}, {deny, all}]},
|
||||
%% {access, register, [{deny, all}]}
|
||||
%% ]
|
||||
%%}.
|
||||
|
||||
|
||||
%%%. ================
|
||||
%%%' DEFAULT LANGUAGE
|
||||
|
||||
%%
|
||||
%% language: Default language used for server messages.
|
||||
%%
|
||||
{language, "en"}.
|
||||
|
||||
%%
|
||||
%% Set a different default language in a virtual host.
|
||||
%%
|
||||
%%{host_config, "localhost",
|
||||
%% [{language, "ru"}]
|
||||
%%}.
|
||||
|
||||
|
||||
%%%. =======
|
||||
%%%' CAPTCHA
|
||||
|
||||
%%
|
||||
%% Full path to a script that generates the image.
|
||||
%%
|
||||
%%{captcha_cmd, "/lib/ejabberd/priv/bin/captcha.sh"}.
|
||||
|
||||
%%
|
||||
%% Host for the URL and port where ejabberd listens for CAPTCHA requests.
|
||||
%%
|
||||
%%{captcha_host, "example.org:5280"}.
|
||||
|
||||
%%
|
||||
%% Limit CAPTCHA calls per minute for JID/IP to avoid DoS.
|
||||
%%
|
||||
%%{captcha_limit, 5}.
|
||||
|
||||
%%%. =======
|
||||
%%%' MODULES
|
||||
|
||||
%%
|
||||
%% Modules enabled in all ejabberd virtual hosts.
|
||||
%%
|
||||
{modules,
|
||||
[
|
||||
{mod_adhoc, []},
|
||||
{mod_announce, [{access, announce}]}, % recommends mod_adhoc
|
||||
{mod_blocking,[]}, % requires mod_privacy
|
||||
{mod_caps, []},
|
||||
{mod_configure,[]}, % requires mod_adhoc
|
||||
{mod_disco, []},
|
||||
%%{mod_echo, [{host, "echo.localhost"}]},
|
||||
{mod_irc, []},
|
||||
{mod_http_bind, []},
|
||||
%%{mod_http_fileserver, [
|
||||
%% {docroot, "/var/www"},
|
||||
%% {accesslog, "/var/log/ejabberd/access.log"}
|
||||
%% ]},
|
||||
{mod_last, []},
|
||||
{mod_muc, [
|
||||
%%{host, "conference.@HOST@"},
|
||||
{access, muc},
|
||||
{access_create, muc_create},
|
||||
{access_persistent, muc_create},
|
||||
{access_admin, muc_admin}
|
||||
]},
|
||||
%%{mod_muc_log,[]},
|
||||
{mod_offline, [{access_max_user_messages, max_user_offline_messages}]},
|
||||
{mod_ping, []},
|
||||
%%{mod_pres_counter,[{count, 5}, {interval, 60}]},
|
||||
{mod_privacy, []},
|
||||
{mod_private, []},
|
||||
%%{mod_proxy65,[]},
|
||||
{mod_pubsub, [
|
||||
{access_createnode, pubsub_createnode},
|
||||
{ignore_pep_from_offline, true}, % reduces resource comsumption, but XEP incompliant
|
||||
%%{ignore_pep_from_offline, false}, % XEP compliant, but increases resource comsumption
|
||||
{last_item_cache, false},
|
||||
{plugins, ["flat", "hometree", "pep"]} % pep requires mod_caps
|
||||
]},
|
||||
{mod_register, [
|
||||
%%
|
||||
%% Protect In-Band account registrations with CAPTCHA.
|
||||
%%
|
||||
%%{captcha_protected, true},
|
||||
|
||||
%%
|
||||
%% Set the minimum informational entropy for passwords.
|
||||
%%
|
||||
%%{password_strength, 32},
|
||||
|
||||
%%
|
||||
%% After successful registration, the user receives
|
||||
%% a message with this subject and body.
|
||||
%%
|
||||
{welcome_message, {"Welcome!",
|
||||
"Hi.\nWelcome to this XMPP server."}},
|
||||
|
||||
%%
|
||||
%% When a user registers, send a notification to
|
||||
%% these XMPP accounts.
|
||||
%%
|
||||
%%{registration_watchers, ["admin1@example.org"]},
|
||||
|
||||
%%
|
||||
%% Only clients in the server machine can register accounts
|
||||
%%
|
||||
{ip_access, [{allow, "127.0.0.0/8"},
|
||||
{deny, "0.0.0.0/0"}]},
|
||||
|
||||
%%
|
||||
%% Local c2s or remote s2s users cannot register accounts
|
||||
%%
|
||||
%%{access_from, deny},
|
||||
|
||||
{access, register}
|
||||
]},
|
||||
%%{mod_register_web, [
|
||||
%%
|
||||
%% When a user registers, send a notification to
|
||||
%% these XMPP accounts.
|
||||
%%
|
||||
%%{registration_watchers, ["admin1@example.org"]}
|
||||
%% ]},
|
||||
{mod_roster, []},
|
||||
%%{mod_service_log,[]},
|
||||
{mod_shared_roster,[]},
|
||||
{mod_stats, []},
|
||||
{mod_time, []},
|
||||
{mod_vcard, []},
|
||||
{mod_version, []}
|
||||
]}.
|
||||
|
||||
%%
|
||||
%% Enable modules with custom options in a specific virtual host
|
||||
%%
|
||||
%%{host_config, "localhost",
|
||||
%% [{{add, modules},
|
||||
%% [
|
||||
%% {mod_echo, [{host, "mirror.localhost"}]}
|
||||
%% ]
|
||||
%% }
|
||||
%% ]}.
|
||||
|
||||
|
||||
%%%.
|
||||
%%%'
|
||||
|
||||
%%% $Id$
|
||||
|
||||
%%% Local Variables:
|
||||
%%% mode: erlang
|
||||
%%% End:
|
||||
%%% vim: set filetype=erlang tabstop=8 foldmarker=%%%',%%%. foldmethod=marker:
|
615
ejabberd.yml.example
Normal file
615
ejabberd.yml.example
Normal file
@ -0,0 +1,615 @@
|
||||
###
|
||||
### ejabberd configuration file
|
||||
###
|
||||
###
|
||||
|
||||
### The parameters used in this configuration file are explained in more detail
|
||||
### in the ejabberd Installation and Operation Guide.
|
||||
### Please consult the Guide in case of doubts, it is included with
|
||||
### your copy of ejabberd, and is also available online at
|
||||
### http://www.process-one.net/en/ejabberd/docs/
|
||||
|
||||
### The configuration file is written in YAML.
|
||||
### Refer to http://en.wikipedia.org/wiki/YAML for the brief description.
|
||||
### However, ejabberd treats different literals as different types:
|
||||
###
|
||||
### - unquoted or single-quoted strings. They are called "atoms".
|
||||
### Example: dog, 'Jupiter', '3.14159', YELLOW
|
||||
###
|
||||
### - numeric literals. Example: 3, -45.0, .0
|
||||
###
|
||||
### - quoted or folded strings.
|
||||
### Examples of quoted string: "Lizzard", "orange".
|
||||
### Example of folded string:
|
||||
### > Art thou not Romeo,
|
||||
### and a Montague?
|
||||
|
||||
### =========
|
||||
### DEBUGGING
|
||||
|
||||
##
|
||||
## loglevel: Verbosity of log files generated by ejabberd.
|
||||
## 0: No ejabberd log at all (not recommended)
|
||||
## 1: Critical
|
||||
## 2: Error
|
||||
## 3: Warning
|
||||
## 4: Info
|
||||
## 5: Debug
|
||||
##
|
||||
loglevel: 4
|
||||
|
||||
##
|
||||
## watchdog_admins: Only useful for developers: if an ejabberd process
|
||||
## consumes a lot of memory, send live notifications to these XMPP
|
||||
## accounts.
|
||||
##
|
||||
## watchdog_admins:
|
||||
## - "bob@example.com"
|
||||
|
||||
|
||||
### ================
|
||||
### SERVED HOSTNAMES
|
||||
|
||||
##
|
||||
## hosts: Domains served by ejabberd.
|
||||
## You can define one or several, for example:
|
||||
## hosts:
|
||||
## - "example.net"
|
||||
## - "example.com"
|
||||
## - "example.org"
|
||||
##
|
||||
hosts:
|
||||
- "localhost"
|
||||
|
||||
##
|
||||
## route_subdomains: Delegate subdomains to other XMPP servers.
|
||||
## For example, if this ejabberd serves example.org and you want
|
||||
## to allow communication with an XMPP server called im.example.org.
|
||||
##
|
||||
## route_subdomains: s2s
|
||||
|
||||
### ===============
|
||||
### LISTENING PORTS
|
||||
|
||||
##
|
||||
## listen: The ports ejabberd will listen on, which service each is handled
|
||||
## by and what options to start it with.
|
||||
##
|
||||
listen:
|
||||
-
|
||||
port: 5222
|
||||
module: ejabberd_c2s
|
||||
##
|
||||
## If TLS is compiled in and you installed a SSL
|
||||
## certificate, specify the full path to the
|
||||
## file and uncomment this line:
|
||||
##
|
||||
## certfile: "/path/to/ssl.pem"
|
||||
## starttls: true
|
||||
max_stanza_size: 65536
|
||||
shaper: c2s_shaper
|
||||
access: c2s
|
||||
-
|
||||
port: 5269
|
||||
module: ejabberd_s2s_in
|
||||
##
|
||||
## ejabberd_service: Interact with external components (transports, ...)
|
||||
##
|
||||
## -
|
||||
## port: 8888
|
||||
## module: ejabberd_service
|
||||
## access: all
|
||||
## shaper_rule: fast
|
||||
## ip: "127.0.0.1"
|
||||
## hosts:
|
||||
## "icq.example.org":
|
||||
## password: "secret"
|
||||
## "sms.example.org":
|
||||
## password: "secret"
|
||||
|
||||
##
|
||||
## ejabberd_stun: Handles STUN Binding requests
|
||||
##
|
||||
## -
|
||||
## port: 3478
|
||||
## transport: udp
|
||||
## module: ejabberd_stun
|
||||
|
||||
##
|
||||
## To handle XML-RPC requests that provide admin credentials:
|
||||
##
|
||||
## -
|
||||
## port: 4560
|
||||
## module: ejabberd_xmlrpc
|
||||
-
|
||||
port: 5280
|
||||
module: ejabberd_http
|
||||
## request_handlers:
|
||||
## "/pub/archive": mod_http_fileserver
|
||||
web_admin: true
|
||||
http_poll: true
|
||||
http_bind: true
|
||||
## register: true
|
||||
captcha: true
|
||||
|
||||
##
|
||||
## s2s_use_starttls: Enable STARTTLS + Dialback for S2S connections.
|
||||
## Allowed values are: false optional required required_trusted
|
||||
## You must specify a certificate file.
|
||||
##
|
||||
## s2s_use_starttls: optional
|
||||
|
||||
##
|
||||
## s2s_certfile: Specify a certificate file.
|
||||
##
|
||||
## s2s_certfile: "/path/to/ssl.pem"
|
||||
|
||||
##
|
||||
## domain_certfile: Specify a different certificate for each served hostname.
|
||||
##
|
||||
## host_config:
|
||||
## "example.org":
|
||||
## domain_certfile: "/path/to/example_org.pem"
|
||||
## "example.com":
|
||||
## domain_certfile: "/path/to/example_com.pem"
|
||||
|
||||
##
|
||||
## S2S whitelist or blacklist
|
||||
##
|
||||
## Default s2s policy for undefined hosts.
|
||||
##
|
||||
## s2s_policy: s2s_access
|
||||
|
||||
##
|
||||
## Outgoing S2S options
|
||||
##
|
||||
## Preferred address families (which to try first) and connect timeout
|
||||
## in milliseconds.
|
||||
##
|
||||
## outgoing_s2s_families:
|
||||
## - ipv4
|
||||
## - ipv6
|
||||
## outgoing_s2s_timeout: 10000
|
||||
|
||||
### ==============
|
||||
### AUTHENTICATION
|
||||
|
||||
##
|
||||
## auth_method: Method used to authenticate the users.
|
||||
## The default method is the internal.
|
||||
## If you want to use a different method,
|
||||
## comment this line and enable the correct ones.
|
||||
##
|
||||
auth_method: internal
|
||||
|
||||
##
|
||||
## Store the plain passwords or hashed for SCRAM:
|
||||
## auth_password_format: plain
|
||||
## auth_password_format: scram
|
||||
##
|
||||
## Define the FQDN if ejabberd doesn't detect it:
|
||||
## fqdn: "server3.example.com"
|
||||
|
||||
##
|
||||
## Authentication using external script
|
||||
## Make sure the script is executable by ejabberd.
|
||||
##
|
||||
## auth_method: external
|
||||
## extauth_program: "/path/to/authentication/script"
|
||||
|
||||
##
|
||||
## Authentication using ODBC
|
||||
## Remember to setup a database in the next section.
|
||||
##
|
||||
## auth_method: odbc
|
||||
|
||||
##
|
||||
## Authentication using PAM
|
||||
##
|
||||
## auth_method: pam
|
||||
## pam_service: "pamservicename"
|
||||
|
||||
##
|
||||
## Authentication using LDAP
|
||||
##
|
||||
## auth_method: ldap
|
||||
##
|
||||
## List of LDAP servers:
|
||||
## ldap_servers:
|
||||
## - "localhost"
|
||||
##
|
||||
## Encryption of connection to LDAP servers:
|
||||
## ldap_encrypt: none
|
||||
## ldap_encrypt: tls
|
||||
##
|
||||
## Port to connect to on LDAP servers:
|
||||
## ldap_port: 389
|
||||
## ldap_port: 636
|
||||
##
|
||||
## LDAP manager:
|
||||
## ldap_rootdn: "dc=example,dc=com"
|
||||
##
|
||||
## Password of LDAP manager:
|
||||
## ldap_password: "******"
|
||||
##
|
||||
## Search base of LDAP directory:
|
||||
## ldap_base: "dc=example,dc=com"
|
||||
##
|
||||
## LDAP attribute that holds user ID:
|
||||
## ldap_uids:
|
||||
## - "mail": "%u@mail.example.org"
|
||||
##
|
||||
## LDAP filter:
|
||||
## ldap_filter: "(objectClass=shadowAccount)"
|
||||
|
||||
##
|
||||
## Anonymous login support:
|
||||
## auth_method: anonymous
|
||||
## anonymous_protocol: sasl_anon | login_anon | both
|
||||
## allow_multiple_connections: true | false
|
||||
##
|
||||
## host_config:
|
||||
## "public.example.org":
|
||||
## auth_method: anonymous
|
||||
## allow_multiple_connections: false
|
||||
## anonymous_protocol: sasl_anon
|
||||
##
|
||||
## To use both anonymous and internal authentication:
|
||||
##
|
||||
## host_config:
|
||||
## "public.example.org":
|
||||
## auth_method:
|
||||
## - internal
|
||||
## - anonymous
|
||||
|
||||
### ==============
|
||||
### DATABASE SETUP
|
||||
|
||||
## ejabberd by default uses the internal Mnesia database,
|
||||
## so you do not necessarily need this section.
|
||||
## This section provides configuration examples in case
|
||||
## you want to use other database backends.
|
||||
## Please consult the ejabberd Guide for details on database creation.
|
||||
|
||||
##
|
||||
## MySQL server:
|
||||
##
|
||||
## odbc_type: mysql
|
||||
## odbc_server: "server"
|
||||
## odbc_database: "database"
|
||||
## odbc_username: "username"
|
||||
## odbc_password: "password"
|
||||
##
|
||||
## If you want to specify the port:
|
||||
## odbc_port: 1234
|
||||
|
||||
##
|
||||
## PostgreSQL server:
|
||||
##
|
||||
## odbc_type: pgsql
|
||||
## odbc_server: "server"
|
||||
## odbc_database: "database"
|
||||
## odbc_username: "username"
|
||||
## odbc_password: "password"
|
||||
##
|
||||
## If you want to specify the port:
|
||||
## odbc_port: 1234
|
||||
##
|
||||
## If you use PostgreSQL, have a large database, and need a
|
||||
## faster but inexact replacement for "select count(*) from users"
|
||||
##
|
||||
## pgsql_users_number_estimate: true
|
||||
|
||||
##
|
||||
## ODBC compatible or MSSQL server:
|
||||
##
|
||||
## odbc_type: odbc
|
||||
## odbc_server: "DSN=ejabberd;UID=ejabberd;PWD=ejabberd"
|
||||
|
||||
##
|
||||
## Number of connections to open to the database for each virtual host
|
||||
##
|
||||
## odbc_pool_size: 10
|
||||
|
||||
##
|
||||
## Interval to make a dummy SQL request to keep the connections to the
|
||||
## database alive. Specify in seconds: for example 28800 means 8 hours
|
||||
##
|
||||
## odbc_keepalive_interval: undefined
|
||||
|
||||
### ===============
|
||||
### TRAFFIC SHAPERS
|
||||
|
||||
shaper:
|
||||
##
|
||||
## The "normal" shaper limits traffic speed to 1000 B/s
|
||||
##
|
||||
normal: 1000
|
||||
|
||||
##
|
||||
## The "fast" shaper limits traffic speed to 50000 B/s
|
||||
##
|
||||
fast: 50000
|
||||
|
||||
##
|
||||
## This option specifies the maximum number of elements in the queue
|
||||
## of the FSM. Refer to the documentation for details.
|
||||
##
|
||||
max_fsm_queue: 1000
|
||||
|
||||
###. ====================
|
||||
###' ACCESS CONTROL LISTS
|
||||
acl:
|
||||
##
|
||||
## The 'admin' ACL grants administrative privileges to XMPP accounts.
|
||||
## You can put here as many accounts as you want.
|
||||
##
|
||||
## admin:
|
||||
## user:
|
||||
## - "aleksey": "localhost"
|
||||
## - "ermine": "example.org"
|
||||
##
|
||||
## Blocked users
|
||||
##
|
||||
## blocked:
|
||||
## user:
|
||||
## - "baduser": "example.org"
|
||||
## - "test": global
|
||||
|
||||
## Local users: don't modify this.
|
||||
##
|
||||
local:
|
||||
user_regexp:
|
||||
- "": global
|
||||
|
||||
##
|
||||
## More examples of ACLs
|
||||
##
|
||||
## jabberorg:
|
||||
## server:
|
||||
## - "jabber.org"
|
||||
## aleksey:
|
||||
## user:
|
||||
## - "aleksey": "jabber.ru"
|
||||
## test:
|
||||
## user_regexp:
|
||||
## - "^test": global
|
||||
## user_glob:
|
||||
## - "test*": global
|
||||
|
||||
##
|
||||
## Loopback network
|
||||
##
|
||||
loopback:
|
||||
ip:
|
||||
- "127.0.0.0/8"
|
||||
|
||||
##
|
||||
## Bad XMPP servers
|
||||
##
|
||||
## bad_servers:
|
||||
## server:
|
||||
## - "xmpp.zombie.org"
|
||||
## - "xmpp.spam.com"
|
||||
|
||||
##
|
||||
## Define specific ACLs in a virtual host.
|
||||
##
|
||||
## host_config:
|
||||
## "localhost":
|
||||
## acl:
|
||||
## admin:
|
||||
## user:
|
||||
## - "bob-local": "localhost"
|
||||
|
||||
### ============
|
||||
### ACCESS RULES
|
||||
access:
|
||||
## Maximum number of simultaneous sessions allowed for a single user:
|
||||
max_user_sessions:
|
||||
all: 10
|
||||
## Maximum number of offline messages that users can have:
|
||||
max_user_offline_messages:
|
||||
admin: 5000
|
||||
all: 100
|
||||
## This rule allows access only for local users:
|
||||
local:
|
||||
local: allow
|
||||
## Only non-blocked users can use c2s connections:
|
||||
c2s:
|
||||
blocked: deny
|
||||
all: allow
|
||||
## For C2S connections, all users except admins use the "normal" shaper
|
||||
c2s_shaper:
|
||||
admin: none
|
||||
all: normal
|
||||
## All S2S connections use the "fast" shaper
|
||||
s2s_shaper:
|
||||
all: fast
|
||||
## Only admins can send announcement messages:
|
||||
announce:
|
||||
admin: allow
|
||||
## Only admins can use the configuration interface:
|
||||
configure:
|
||||
admin: allow
|
||||
## Admins of this server are also admins of the MUC service:
|
||||
muc_admin:
|
||||
admin: allow
|
||||
## Only accounts of the local ejabberd server can create rooms:
|
||||
muc_create:
|
||||
local: allow
|
||||
## All users are allowed to use the MUC service:
|
||||
muc:
|
||||
all: allow
|
||||
## Only accounts on the local ejabberd server can create Pubsub nodes:
|
||||
pubsub_createnode:
|
||||
local: allow
|
||||
## In-band registration allows registration of any possible username.
|
||||
## To disable in-band registration, replace 'allow' with 'deny'.
|
||||
register:
|
||||
all: allow
|
||||
## Only allow to register from localhost
|
||||
trusted_network:
|
||||
loopback: allow
|
||||
## Do not establish S2S connections with bad servers
|
||||
## s2s_access:
|
||||
## bad_servers: deny
|
||||
## all: allow
|
||||
|
||||
## By default the frequency of account registrations from the same IP
|
||||
## is limited to 1 account every 10 minutes. To disable, specify: infinity
|
||||
## registration_timeout: 600
|
||||
|
||||
##
|
||||
## Define specific Access Rules in a virtual host.
|
||||
##
|
||||
## host_config:
|
||||
## "localhost":
|
||||
## access:
|
||||
## c2s:
|
||||
## admin: allow
|
||||
## all: deny
|
||||
## register:
|
||||
## all: deny
|
||||
|
||||
### ================
|
||||
### DEFAULT LANGUAGE
|
||||
|
||||
##
|
||||
## language: Default language used for server messages.
|
||||
##
|
||||
language: "en"
|
||||
|
||||
##
|
||||
## Set a different default language in a virtual host.
|
||||
##
|
||||
## host_config:
|
||||
## "localhost":
|
||||
## language: "ru"
|
||||
|
||||
### =======
|
||||
### CAPTCHA
|
||||
|
||||
##
|
||||
## Full path to a script that generates the image.
|
||||
##
|
||||
## captcha_cmd: "/lib/ejabberd/priv/bin/captcha.sh"
|
||||
|
||||
##
|
||||
## Host for the URL and port where ejabberd listens for CAPTCHA requests.
|
||||
##
|
||||
## captcha_host: "example.org:5280"
|
||||
|
||||
##
|
||||
## Limit CAPTCHA calls per minute for JID/IP to avoid DoS.
|
||||
##
|
||||
## captcha_limit: 5
|
||||
|
||||
### =======
|
||||
### MODULES
|
||||
|
||||
##
|
||||
## Modules enabled in all ejabberd virtual hosts.
|
||||
##
|
||||
modules:
|
||||
mod_adhoc: {}
|
||||
mod_announce: # recommends mod_adhoc
|
||||
access: announce
|
||||
mod_blocking: {} # requires mod_privacy
|
||||
mod_caps: {}
|
||||
mod_configure: {} # requires mod_adhoc
|
||||
mod_disco: {}
|
||||
## mod_echo: {}
|
||||
mod_irc: {}
|
||||
mod_http_bind: {}
|
||||
## mod_http_fileserver:
|
||||
## docroot: "/var/www"
|
||||
## accesslog: "/var/log/ejabberd/access.log"
|
||||
mod_last: {}
|
||||
mod_muc:
|
||||
## host: "conference.@HOST@"
|
||||
access: muc
|
||||
access_create: muc_create
|
||||
access_persistent: muc_create
|
||||
access_admin: muc_admin
|
||||
## mod_muc_log: {}
|
||||
mod_offline:
|
||||
access_max_user_messages: max_user_offline_messages
|
||||
mod_ping: {}
|
||||
## mod_pres_counter:
|
||||
## count: 5
|
||||
## interval: 60
|
||||
mod_privacy: {}
|
||||
mod_private: {}
|
||||
## mod_proxy65: {}
|
||||
mod_pubsub:
|
||||
access_createnode: pubsub_createnode
|
||||
## reduces resource comsumption, but XEP incompliant
|
||||
ignore_pep_from_offline: true
|
||||
## XEP compliant, but increases resource comsumption
|
||||
## ignore_pep_from_offline: false
|
||||
last_item_cache: false
|
||||
plugins:
|
||||
- "flat"
|
||||
- "hometree"
|
||||
- "pep" # pep requires mod_caps
|
||||
mod_register:
|
||||
##
|
||||
## Protect In-Band account registrations with CAPTCHA.
|
||||
##
|
||||
## captcha_protected: true
|
||||
|
||||
##
|
||||
## Set the minimum informational entropy for passwords.
|
||||
##
|
||||
## password_strength: 32
|
||||
|
||||
##
|
||||
## After successful registration, the user receives
|
||||
## a message with this subject and body.
|
||||
##
|
||||
welcome_message:
|
||||
subject: "Welcome!"
|
||||
body: |-
|
||||
Hi.
|
||||
Welcome to this XMPP server.
|
||||
|
||||
##
|
||||
## When a user registers, send a notification to
|
||||
## these XMPP accounts.
|
||||
##
|
||||
## registration_watchers:
|
||||
## - "admin1@example.org"
|
||||
|
||||
##
|
||||
## Only clients in the server machine can register accounts
|
||||
##
|
||||
ip_access: trusted_network
|
||||
|
||||
##
|
||||
## Local c2s or remote s2s users cannot register accounts
|
||||
##
|
||||
## access_from: deny
|
||||
|
||||
access: register
|
||||
mod_roster: {}
|
||||
mod_shared_roster: {}
|
||||
mod_stats: {}
|
||||
mod_time: {}
|
||||
mod_vcard: {}
|
||||
mod_version: {}
|
||||
|
||||
##
|
||||
## Enable modules with custom options in a specific virtual host
|
||||
##
|
||||
## host_config:
|
||||
## "localhost":
|
||||
## add:
|
||||
## modules:
|
||||
## mod_echo:
|
||||
## host: "mirror.localhost"
|
||||
|
||||
### Local Variables:
|
||||
### mode: yaml
|
||||
### End:
|
||||
### vim: set filetype=yaml tabstop=8
|
@ -65,7 +65,7 @@ if [ -f "$EJABBERDCTL_CONFIG_PATH" ] ; then
|
||||
. "$EJABBERDCTL_CONFIG_PATH"
|
||||
fi
|
||||
if [ "$EJABBERD_CONFIG_PATH" = "" ] ; then
|
||||
EJABBERD_CONFIG_PATH=$ETCDIR/ejabberd.cfg
|
||||
EJABBERD_CONFIG_PATH=$ETCDIR/ejabberd.yml
|
||||
fi
|
||||
if [ "$LOGS_DIR" = "" ] ; then
|
||||
LOGS_DIR={{localstatedir}}/log/ejabberd
|
||||
|
@ -56,6 +56,7 @@ Deps = [{p1_cache_tab, ".*", {git, "git://github.com/processone/cache_tab"}},
|
||||
{p1_tls, ".*", {git, "git://github.com/processone/tls"}},
|
||||
{p1_stringprep, ".*", {git, "git://github.com/processone/stringprep"}},
|
||||
{p1_xml, ".*", {git, "git://github.com/processone/xml"}},
|
||||
{p1_yaml, ".*", {git, "git://github.com/processone/p1_yaml"}},
|
||||
{xmlrpc, ".*", {git, "git://github.com/rds13/xmlrpc"}}],
|
||||
|
||||
ConfigureCmd = fun(Pkg, Flags) ->
|
||||
|
@ -28,7 +28,7 @@ ConfiguredOTPApps = lists:flatmap(
|
||||
|
||||
OTPApps = RequiredOTPApps ++ ConfiguredOTPApps,
|
||||
|
||||
DepRequiredApps = [p1_cache_tab, p1_tls, p1_stringprep, p1_xml, xmlrpc],
|
||||
DepRequiredApps = [p1_cache_tab, p1_tls, p1_stringprep, p1_xml, p1_yaml, xmlrpc],
|
||||
|
||||
DepConfiguredApps = lists:flatmap(
|
||||
fun({mysql, true}) -> [p1_mysql];
|
||||
@ -39,7 +39,7 @@ DepConfiguredApps = lists:flatmap(
|
||||
({json, true}) -> [jiffy];
|
||||
({iconv, true}) -> [p1_iconv];
|
||||
({http, true}) -> [ibrowse, lhttpc];
|
||||
({lager, true}) -> [lager];
|
||||
({lager, true}) -> [lager, goldrush];
|
||||
({lager, false}) -> [p1_logger];
|
||||
(_) -> []
|
||||
end, Vars),
|
||||
@ -89,7 +89,7 @@ Overlay = [
|
||||
{template, "files/erl", "\{\{erts_vsn\}\}/bin/erl"},
|
||||
{template, "../ejabberdctl.template", "bin/ejabberdctl"},
|
||||
{copy, "../ejabberdctl.cfg.example", "etc/ejabberd/ejabberdctl.cfg"},
|
||||
{copy, "../ejabberd.cfg.example", "etc/ejabberd/ejabberd.cfg"},
|
||||
{copy, "../ejabberd.yml.example", "etc/ejabberd/ejabberd.yml"},
|
||||
{copy, "../inetrc", "etc/ejabberd/inetrc"},
|
||||
{copy, "files/install_upgrade.escript", "bin/install_upgrade.escript"}
|
||||
],
|
||||
|
463
src/acl.erl
463
src/acl.erl
@ -29,35 +29,38 @@
|
||||
-author('alexey@process-one.net').
|
||||
|
||||
-export([start/0, to_record/3, add/3, add_list/3,
|
||||
add_local/3, add_list_local/3,
|
||||
match_rule/3, match_acl/3]).
|
||||
add_local/3, add_list_local/3, load_from_config/0,
|
||||
match_rule/3, match_acl/3, transform_options/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("jlib.hrl").
|
||||
|
||||
-record(acl, {aclname, aclspec}).
|
||||
-record(access, {name :: access_name(),
|
||||
rules = [] :: [access_rule()]}).
|
||||
|
||||
-type regexp() :: binary().
|
||||
-type glob() :: binary().
|
||||
-type access_name() :: atom().
|
||||
-type access_rule() :: {atom(), any()}.
|
||||
-type host() :: binary().
|
||||
-type aclname() :: {atom(), binary() | global}.
|
||||
-type aclspec() :: all | none |
|
||||
{user, binary()} |
|
||||
{user, binary(), binary()} |
|
||||
{user, {binary(), host()} | binary()} |
|
||||
{server, binary()} |
|
||||
{resource, binary()} |
|
||||
{user_regexp, regexp()} |
|
||||
{shared_group, binary()} |
|
||||
{shared_group, binary(), binary()} |
|
||||
{user_regexp, regexp(), binary()} |
|
||||
{user_regexp, {regexp(), host()} | regexp()} |
|
||||
{shared_group, {binary(), host()} | binary()} |
|
||||
{user_regexp, {regexp(), host()} | regexp()} |
|
||||
{server_regexp, regexp()} |
|
||||
{resource_regexp, regexp()} |
|
||||
{node_regexp, regexp(), regexp()} |
|
||||
{user_glob, glob()} |
|
||||
{user_glob, glob(), binary()} |
|
||||
{node_regexp, {regexp(), regexp()}} |
|
||||
{user_glob, {glob(), host()} | glob()} |
|
||||
{server_glob, glob()} |
|
||||
{resource_glob, glob()} |
|
||||
{node_glob, glob(), glob()}.
|
||||
{ip, {inet:ip_address(), integer()}} |
|
||||
{node_glob, {glob(), glob()}}.
|
||||
|
||||
-type acl() :: #acl{aclname :: aclname(),
|
||||
aclspec :: aclspec()}.
|
||||
@ -65,12 +68,23 @@
|
||||
-export_type([acl/0]).
|
||||
|
||||
start() ->
|
||||
case catch mnesia:table_info(acl, storage_type) of
|
||||
disc_copies ->
|
||||
mnesia:delete_table(acl);
|
||||
_ ->
|
||||
ok
|
||||
end,
|
||||
mnesia:create_table(acl,
|
||||
[{disc_copies, [node()]}, {type, bag},
|
||||
[{ram_copies, [node()]}, {type, bag},
|
||||
{local_content, true},
|
||||
{attributes, record_info(fields, acl)}]),
|
||||
mnesia:create_table(access,
|
||||
[{ram_copies, [node()]},
|
||||
{local_content, true},
|
||||
{attributes, record_info(fields, access)}]),
|
||||
mnesia:add_table_copy(acl, node(), ram_copies),
|
||||
update_table(),
|
||||
mnesia:add_table_copy(access, node(), ram_copies),
|
||||
load_from_config(),
|
||||
ok.
|
||||
|
||||
-spec to_record(binary(), atom(), aclspec()) -> acl().
|
||||
@ -82,7 +96,7 @@ to_record(Host, ACLName, ACLSpec) ->
|
||||
-spec add(binary(), aclname(), aclspec()) -> ok | {error, any()}.
|
||||
|
||||
add(Host, ACLName, ACLSpec) ->
|
||||
{ResL, BadNodes} = rpc:multicall(ejabberd_cluster:get_nodes(),
|
||||
{ResL, BadNodes} = rpc:multicall(mnesia:system_info(running_db_nodes),
|
||||
?MODULE, add_local,
|
||||
[Host, ACLName, ACLSpec]),
|
||||
case lists:keyfind(aborted, 1, ResL) of
|
||||
@ -109,7 +123,7 @@ add_local(Host, ACLName, ACLSpec) ->
|
||||
-spec add_list(binary(), [acl()], boolean()) -> ok | {error, any()}.
|
||||
|
||||
add_list(Host, ACLs, Clear) ->
|
||||
{ResL, BadNodes} = rpc:multicall(ejabberd_cluster:get_nodes(),
|
||||
{ResL, BadNodes} = rpc:multicall(mnesia:system_info(running_db_nodes),
|
||||
?MODULE, add_list_local,
|
||||
[Host, ACLs, Clear]),
|
||||
case lists:keyfind(aborted, 1, ResL) of
|
||||
@ -147,130 +161,196 @@ add_list_local(Host, ACLs, Clear) ->
|
||||
end,
|
||||
mnesia:transaction(F).
|
||||
|
||||
normalize(A) -> jlib:nodeprep(iolist_to_binary(A)).
|
||||
-spec add_access(binary() | global,
|
||||
access_name(), [access_rule()]) -> ok | {error, any()}.
|
||||
|
||||
normalize_spec({A, B}) -> {A, normalize(B)};
|
||||
normalize_spec({A, B, C}) ->
|
||||
{A, normalize(B), normalize(C)};
|
||||
normalize_spec(all) -> all;
|
||||
normalize_spec(none) -> none.
|
||||
add_access(Host, Access, Rules) ->
|
||||
case mnesia:transaction(
|
||||
fun() ->
|
||||
mnesia:write(
|
||||
#access{name = {Access, Host},
|
||||
rules = Rules})
|
||||
end) of
|
||||
{atomic, ok} ->
|
||||
ok;
|
||||
Err ->
|
||||
{error, Err}
|
||||
end.
|
||||
|
||||
-spec match_rule(global | binary(), atom(), jid() | ljid()) -> any().
|
||||
-spec load_from_config() -> ok.
|
||||
|
||||
match_rule(global, Rule, JID) ->
|
||||
case Rule of
|
||||
all -> allow;
|
||||
none -> deny;
|
||||
_ ->
|
||||
case ejabberd_config:get_global_option(
|
||||
{access, Rule, global}, fun(V) -> V end)
|
||||
of
|
||||
undefined -> deny;
|
||||
GACLs -> match_acls(GACLs, JID, global)
|
||||
end
|
||||
end;
|
||||
match_rule(Host, Rule, JID) ->
|
||||
case Rule of
|
||||
all -> allow;
|
||||
none -> deny;
|
||||
_ ->
|
||||
case ejabberd_config:get_global_option(
|
||||
{access, Rule, global}, fun(V) -> V end)
|
||||
of
|
||||
undefined ->
|
||||
case ejabberd_config:get_global_option(
|
||||
{access, Rule, Host}, fun(V) -> V end)
|
||||
of
|
||||
undefined -> deny;
|
||||
ACLs -> match_acls(ACLs, JID, Host)
|
||||
end;
|
||||
GACLs ->
|
||||
case ejabberd_config:get_global_option(
|
||||
{access, Rule, Host}, fun(V) -> V end)
|
||||
of
|
||||
undefined -> match_acls(GACLs, JID, Host);
|
||||
ACLs ->
|
||||
case lists:reverse(GACLs) of
|
||||
[{allow, all} | Rest] ->
|
||||
match_acls(lists:reverse(Rest) ++
|
||||
ACLs ++ [{allow, all}],
|
||||
JID, Host);
|
||||
_ -> match_acls(GACLs ++ ACLs, JID, Host)
|
||||
end
|
||||
end
|
||||
end
|
||||
load_from_config() ->
|
||||
Hosts = [global|?MYHOSTS],
|
||||
lists:foreach(
|
||||
fun(Host) ->
|
||||
ACLs = ejabberd_config:get_option(
|
||||
{acl, Host}, fun(V) -> V end, []),
|
||||
AccessRules = ejabberd_config:get_option(
|
||||
{access, Host}, fun(V) -> V end, []),
|
||||
lists:foreach(
|
||||
fun({ACLName, SpecList}) ->
|
||||
lists:foreach(
|
||||
fun({ACLType, ACLSpecs}) when is_list(ACLSpecs) ->
|
||||
lists:foreach(
|
||||
fun(ACLSpec) ->
|
||||
add(Host, ACLName,
|
||||
{ACLType, ACLSpec})
|
||||
end, lists:flatten(ACLSpecs));
|
||||
({ACLType, ACLSpecs}) ->
|
||||
add(Host, ACLName, {ACLType, ACLSpecs})
|
||||
end, lists:flatten(SpecList))
|
||||
end, ACLs),
|
||||
lists:foreach(
|
||||
fun({Access, Rules}) ->
|
||||
add_access(Host, Access, Rules)
|
||||
end, AccessRules)
|
||||
end, Hosts).
|
||||
|
||||
b(S) ->
|
||||
iolist_to_binary(S).
|
||||
|
||||
nodeprep(S) ->
|
||||
jlib:nodeprep(b(S)).
|
||||
|
||||
nameprep(S) ->
|
||||
jlib:nameprep(b(S)).
|
||||
|
||||
resourceprep(S) ->
|
||||
jlib:resourceprep(b(S)).
|
||||
|
||||
normalize_spec(Spec) ->
|
||||
case Spec of
|
||||
all -> all;
|
||||
none -> none;
|
||||
{user, {U, S}} -> {user, {nodeprep(U), nameprep(S)}};
|
||||
{user, U} -> {user, nodeprep(U)};
|
||||
{shared_group, {G, H}} -> {shared_group, {b(G), nameprep(H)}};
|
||||
{shared_group, G} -> {shared_group, b(G)};
|
||||
{user_regexp, {UR, S}} -> {user_regexp, {b(UR), nameprep(S)}};
|
||||
{user_regexp, UR} -> {user_regexp, b(UR)};
|
||||
{node_regexp, {UR, SR}} -> {node_regexp, {b(UR), b(SR)}};
|
||||
{user_glob, {UR, S}} -> {user_glob, {b(UR), nameprep(S)}};
|
||||
{user_glob, UR} -> {user_glob, b(UR)};
|
||||
{node_glob, {UR, SR}} -> {node_glob, {b(UR), b(SR)}};
|
||||
{server, S} -> {server, nameprep(S)};
|
||||
{resource, R} -> {resource, resourceprep(R)};
|
||||
{server_regexp, SR} -> {server_regexp, b(SR)};
|
||||
{server_glob, S} -> {server_glob, b(S)};
|
||||
{resource_glob, R} -> {resource_glob, b(R)};
|
||||
{ip, S} ->
|
||||
case parse_ip_netmask(b(S)) of
|
||||
{ok, Net, Mask} ->
|
||||
{ip, {Net, Mask}};
|
||||
error ->
|
||||
?INFO_MSG("Invalid network address: ~p", [S]),
|
||||
none
|
||||
end
|
||||
end.
|
||||
|
||||
-spec match_rule(global | binary(), access_name(),
|
||||
jid() | ljid() | inet:ip_address()) -> any().
|
||||
|
||||
match_rule(_Host, all, _JID) ->
|
||||
allow;
|
||||
match_rule(_Host, none, _JID) ->
|
||||
deny;
|
||||
match_rule(Host, Access, JID) ->
|
||||
GAccess = ets:lookup(access, {Access, global}),
|
||||
LAccess = if Host /= global ->
|
||||
ets:lookup(access, {Access, Host});
|
||||
true ->
|
||||
[]
|
||||
end,
|
||||
case GAccess ++ LAccess of
|
||||
[] ->
|
||||
?WARNING_MSG("Attempt to match against unspecified "
|
||||
"access rule '~s' (scope: ~s)",
|
||||
[Access, Host]),
|
||||
deny;
|
||||
AccessList ->
|
||||
Rules = lists:flatmap(
|
||||
fun(#access{rules = Rs}) ->
|
||||
Rs
|
||||
end, AccessList),
|
||||
match_acls(Rules, JID, Host)
|
||||
end.
|
||||
|
||||
match_acls([], _, _Host) -> deny;
|
||||
match_acls([{Access, ACL} | ACLs], JID, Host) ->
|
||||
match_acls([{ACL, Access} | ACLs], JID, Host) ->
|
||||
case match_acl(ACL, JID, Host) of
|
||||
true -> Access;
|
||||
_ -> match_acls(ACLs, JID, Host)
|
||||
end.
|
||||
|
||||
-spec match_acl(atom(), jid() | ljid(), binary()) -> boolean().
|
||||
-spec match_acl(atom(),
|
||||
jid() | ljid() | inet:ip_address(),
|
||||
binary()) -> boolean().
|
||||
|
||||
match_acl(all, _JID, _Host) ->
|
||||
true;
|
||||
match_acl(none, _JID, _Host) ->
|
||||
false;
|
||||
match_acl(ACL, IP, Host) when tuple_size(IP) == 4;
|
||||
tuple_size(IP) == 8 ->
|
||||
lists:any(
|
||||
fun(#acl{aclspec = {ip, {Net, Mask}}}) ->
|
||||
is_ip_match(IP, Net, Mask);
|
||||
(_) ->
|
||||
false
|
||||
end,
|
||||
ets:lookup(acl, {ACL, Host}) ++
|
||||
ets:lookup(acl, {ACL, global}));
|
||||
match_acl(ACL, JID, Host) ->
|
||||
case ACL of
|
||||
all -> true;
|
||||
none -> false;
|
||||
_ ->
|
||||
{User, Server, Resource} = jlib:jid_tolower(JID),
|
||||
lists:any(fun (#acl{aclspec = Spec}) ->
|
||||
case Spec of
|
||||
all -> true;
|
||||
{user, U} ->
|
||||
U == User andalso
|
||||
(Host == Server orelse
|
||||
Host == global andalso
|
||||
lists:member(Server, ?MYHOSTS));
|
||||
{user, U, S} -> U == User andalso S == Server;
|
||||
{server, S} -> S == Server;
|
||||
{resource, R} -> R == Resource;
|
||||
{user_regexp, UR} ->
|
||||
(Host == Server orelse
|
||||
Host == global andalso
|
||||
lists:member(Server, ?MYHOSTS))
|
||||
andalso is_regexp_match(User, UR);
|
||||
{shared_group, G} ->
|
||||
Mod = loaded_shared_roster_module(Host),
|
||||
Mod:is_user_in_group({User, Server}, G, Host);
|
||||
{shared_group, G, H} ->
|
||||
Mod = loaded_shared_roster_module(H),
|
||||
Mod:is_user_in_group({User, Server}, G, H);
|
||||
{user_regexp, UR, S} ->
|
||||
S == Server andalso is_regexp_match(User, UR);
|
||||
{server_regexp, SR} ->
|
||||
is_regexp_match(Server, SR);
|
||||
{resource_regexp, RR} ->
|
||||
is_regexp_match(Resource, RR);
|
||||
{node_regexp, UR, SR} ->
|
||||
is_regexp_match(Server, SR) andalso
|
||||
is_regexp_match(User, UR);
|
||||
{user_glob, UR} ->
|
||||
(Host == Server orelse
|
||||
Host == global andalso
|
||||
lists:member(Server, ?MYHOSTS))
|
||||
andalso is_glob_match(User, UR);
|
||||
{user_glob, UR, S} ->
|
||||
S == Server andalso is_glob_match(User, UR);
|
||||
{server_glob, SR} -> is_glob_match(Server, SR);
|
||||
{resource_glob, RR} ->
|
||||
is_glob_match(Resource, RR);
|
||||
{node_glob, UR, SR} ->
|
||||
is_glob_match(Server, SR) andalso
|
||||
is_glob_match(User, UR);
|
||||
WrongSpec ->
|
||||
?ERROR_MSG("Wrong ACL expression: ~p~nCheck your "
|
||||
"config file and reload it with the override_a"
|
||||
"cls option enabled",
|
||||
[WrongSpec]),
|
||||
false
|
||||
end
|
||||
end,
|
||||
ets:lookup(acl, {ACL, global}) ++
|
||||
ets:lookup(acl, {ACL, Host}))
|
||||
end.
|
||||
{User, Server, Resource} = jlib:jid_tolower(JID),
|
||||
lists:any(
|
||||
fun(#acl{aclspec = Spec}) ->
|
||||
case Spec of
|
||||
all -> true;
|
||||
{user, {U, S}} -> U == User andalso S == Server;
|
||||
{user, U} ->
|
||||
U == User andalso
|
||||
lists:member(Server, ?MYHOSTS);
|
||||
{server, S} -> S == Server;
|
||||
{resource, R} -> R == Resource;
|
||||
{shared_group, {G, H}} ->
|
||||
Mod = loaded_shared_roster_module(H),
|
||||
Mod:is_user_in_group({User, Server}, G, H);
|
||||
{shared_group, G} ->
|
||||
Mod = loaded_shared_roster_module(Host),
|
||||
Mod:is_user_in_group({User, Server}, G, Host);
|
||||
{user_regexp, {UR, S}} ->
|
||||
S == Server andalso is_regexp_match(User, UR);
|
||||
{user_regexp, UR} ->
|
||||
lists:member(Server, ?MYHOSTS)
|
||||
andalso is_regexp_match(User, UR);
|
||||
{server_regexp, SR} ->
|
||||
is_regexp_match(Server, SR);
|
||||
{resource_regexp, RR} ->
|
||||
is_regexp_match(Resource, RR);
|
||||
{node_regexp, {UR, SR}} ->
|
||||
is_regexp_match(Server, SR) andalso
|
||||
is_regexp_match(User, UR);
|
||||
{user_glob, {UR, S}} ->
|
||||
S == Server andalso is_glob_match(User, UR);
|
||||
{user_glob, UR} ->
|
||||
lists:member(Server, ?MYHOSTS)
|
||||
andalso is_glob_match(User, UR);
|
||||
{server_glob, SR} -> is_glob_match(Server, SR);
|
||||
{resource_glob, RR} ->
|
||||
is_glob_match(Resource, RR);
|
||||
{node_glob, {UR, SR}} ->
|
||||
is_glob_match(Server, SR) andalso
|
||||
is_glob_match(User, UR);
|
||||
WrongSpec ->
|
||||
?ERROR_MSG("Wrong ACL expression: ~p~nCheck your "
|
||||
"config file and reload it with the override_a"
|
||||
"cls option enabled",
|
||||
[WrongSpec]),
|
||||
false
|
||||
end
|
||||
end,
|
||||
ets:lookup(acl, {ACL, Host}) ++
|
||||
ets:lookup(acl, {ACL, global})).
|
||||
|
||||
is_regexp_match(String, RegExp) ->
|
||||
case ejabberd_regexp:run(String, RegExp) of
|
||||
@ -286,34 +366,115 @@ is_glob_match(String, Glob) ->
|
||||
is_regexp_match(String,
|
||||
ejabberd_regexp:sh_to_awk(Glob)).
|
||||
|
||||
is_ip_match({_, _, _, _} = IP, {_, _, _, _} = Net, Mask) ->
|
||||
IPInt = ip_to_integer(IP),
|
||||
NetInt = ip_to_integer(Net),
|
||||
M = bnot (1 bsl (32 - Mask) - 1),
|
||||
IPInt band M =:= NetInt band M;
|
||||
is_ip_match({_, _, _, _, _, _, _, _} = IP,
|
||||
{_, _, _, _, _, _, _, _} = Net, Mask) ->
|
||||
IPInt = ip_to_integer(IP),
|
||||
NetInt = ip_to_integer(Net),
|
||||
M = bnot (1 bsl (128 - Mask) - 1),
|
||||
IPInt band M =:= NetInt band M;
|
||||
is_ip_match(_, _, _) ->
|
||||
false.
|
||||
|
||||
ip_to_integer({IP1, IP2, IP3, IP4}) ->
|
||||
IP1 bsl 8 bor IP2 bsl 8 bor IP3 bsl 8 bor IP4;
|
||||
ip_to_integer({IP1, IP2, IP3, IP4, IP5, IP6, IP7,
|
||||
IP8}) ->
|
||||
IP1 bsl 16 bor IP2 bsl 16 bor IP3 bsl 16 bor IP4 bsl 16
|
||||
bor IP5
|
||||
bsl 16
|
||||
bor IP6
|
||||
bsl 16
|
||||
bor IP7
|
||||
bsl 16
|
||||
bor IP8.
|
||||
|
||||
loaded_shared_roster_module(Host) ->
|
||||
case gen_mod:is_loaded(Host, mod_shared_roster_ldap) of
|
||||
true -> mod_shared_roster_ldap;
|
||||
false -> mod_shared_roster
|
||||
end.
|
||||
|
||||
update_table() ->
|
||||
Fields = record_info(fields, acl),
|
||||
case mnesia:table_info(acl, attributes) of
|
||||
Fields ->
|
||||
ejabberd_config:convert_table_to_binary(
|
||||
acl, Fields, bag,
|
||||
fun(#acl{aclspec = Spec}) when is_tuple(Spec) ->
|
||||
element(2, Spec);
|
||||
(_) ->
|
||||
'$next'
|
||||
end,
|
||||
fun(#acl{aclname = {ACLName, Host},
|
||||
aclspec = Spec} = R) ->
|
||||
NewHost = if Host == global ->
|
||||
Host;
|
||||
true ->
|
||||
iolist_to_binary(Host)
|
||||
end,
|
||||
R#acl{aclname = {ACLName, NewHost},
|
||||
aclspec = normalize_spec(Spec)}
|
||||
end);
|
||||
_ ->
|
||||
?INFO_MSG("Recreating acl table", []),
|
||||
mnesia:transform_table(acl, ignore, Fields)
|
||||
parse_ip_netmask(S) ->
|
||||
case str:tokens(S, <<"/">>) of
|
||||
[IPStr] ->
|
||||
case inet_parse:address(binary_to_list(IPStr)) of
|
||||
{ok, {_, _, _, _} = IP} -> {ok, IP, 32};
|
||||
{ok, {_, _, _, _, _, _, _, _} = IP} -> {ok, IP, 128};
|
||||
_ -> error
|
||||
end;
|
||||
[IPStr, MaskStr] ->
|
||||
case catch jlib:binary_to_integer(MaskStr) of
|
||||
Mask when is_integer(Mask), Mask >= 0 ->
|
||||
case inet_parse:address(binary_to_list(IPStr)) of
|
||||
{ok, {_, _, _, _} = IP} when Mask =< 32 ->
|
||||
{ok, IP, Mask};
|
||||
{ok, {_, _, _, _, _, _, _, _} = IP} when Mask =< 128 ->
|
||||
{ok, IP, Mask};
|
||||
_ -> error
|
||||
end;
|
||||
_ -> error
|
||||
end;
|
||||
_ -> error
|
||||
end.
|
||||
|
||||
transform_options(Opts) ->
|
||||
Opts1 = lists:foldl(fun transform_options/2, [], Opts),
|
||||
{ACLOpts, Opts2} = lists:mapfoldl(
|
||||
fun({acl, Os}, Acc) ->
|
||||
{Os, Acc};
|
||||
(O, Acc) ->
|
||||
{[], [O|Acc]}
|
||||
end, [], Opts1),
|
||||
{AccessOpts, Opts3} = lists:mapfoldl(
|
||||
fun({access, Os}, Acc) ->
|
||||
{Os, Acc};
|
||||
(O, Acc) ->
|
||||
{[], [O|Acc]}
|
||||
end, [], Opts2),
|
||||
ACLOpts1 = ejabberd_config:collect_options(lists:flatten(ACLOpts)),
|
||||
AccessOpts1 = case ejabberd_config:collect_options(
|
||||
lists:flatten(AccessOpts)) of
|
||||
[] -> [];
|
||||
L1 -> [{access, L1}]
|
||||
end,
|
||||
ACLOpts2 = case lists:map(
|
||||
fun({ACLName, Os}) ->
|
||||
{ACLName, ejabberd_config:collect_options(Os)}
|
||||
end, ACLOpts1) of
|
||||
[] -> [];
|
||||
L2 -> [{acl, L2}]
|
||||
end,
|
||||
ACLOpts2 ++ AccessOpts1 ++ Opts3.
|
||||
|
||||
transform_options({acl, Name, Type}, Opts) ->
|
||||
T = case Type of
|
||||
all -> all;
|
||||
none -> none;
|
||||
{user, U} -> {user, [U]};
|
||||
{user, U, S} -> {user, [[{U, S}]]};
|
||||
{shared_group, G} -> {shared_group, [G]};
|
||||
{shared_group, G, H} -> {shared_group, [[{G, H}]]};
|
||||
{user_regexp, UR} -> {user_regexp, [UR]};
|
||||
{user_regexp, UR, S} -> {user_regexp, [[{UR, S}]]};
|
||||
{node_regexp, UR, SR} -> {node_regexp, [[{UR, SR}]]};
|
||||
{user_glob, UR} -> {user_glob, [UR]};
|
||||
{user_glob, UR, S} -> {user_glob, [[{UR, S}]]};
|
||||
{node_glob, UR, SR} -> {node_glob, [[{UR, SR}]]};
|
||||
{server, S} -> {server, [S]};
|
||||
{resource, R} -> {resource, [R]};
|
||||
{server_regexp, SR} -> {server_regexp, [SR]};
|
||||
{server_glob, S} -> {server_glob, [S]};
|
||||
{ip, S} -> {ip, [S]};
|
||||
{resource_glob, R} -> {resource_glob, [R]}
|
||||
end,
|
||||
[{acl, [{Name, [T]}]}|Opts];
|
||||
transform_options({access, Name, Rules}, Opts) ->
|
||||
NewRules = [{ACL, Action} || {Action, ACL} <- Rules],
|
||||
[{access, [{Name, NewRules}]}|Opts];
|
||||
transform_options(Opt, Opts) ->
|
||||
[Opt|Opts].
|
||||
|
@ -204,11 +204,11 @@ get_local_fqdn() ->
|
||||
Str when is_binary(Str) -> Str;
|
||||
_ ->
|
||||
<<"unknown-fqdn, please configure fqdn "
|
||||
"option in ejabberd.cfg!">>
|
||||
"option in ejabberd.yml!">>
|
||||
end.
|
||||
|
||||
get_local_fqdn2() ->
|
||||
case ejabberd_config:get_local_option(
|
||||
case ejabberd_config:get_option(
|
||||
fqdn, fun iolist_to_binary/1) of
|
||||
ConfiguredFqdn when is_binary(ConfiguredFqdn) ->
|
||||
ConfiguredFqdn;
|
||||
|
@ -164,6 +164,12 @@ commands() ->
|
||||
module = ejd2odbc, function = export,
|
||||
args = [{host, string}, {file, string}], result = {res, rescode}},
|
||||
|
||||
#ejabberd_commands{name = convert_to_yaml, tags = [config],
|
||||
desc = "Convert the input file from Erlang to YAML format",
|
||||
module = ejabberd_config, function = convert_to_yaml,
|
||||
args = [{in, string}, {out, string}],
|
||||
result = {res, rescode}},
|
||||
|
||||
#ejabberd_commands{name = delete_expired_messages, tags = [purge],
|
||||
desc = "Delete expired offline messages from database",
|
||||
module = ?MODULE, function = delete_expired_messages,
|
||||
|
@ -47,12 +47,14 @@ start(normal, _Args) ->
|
||||
db_init(),
|
||||
start(),
|
||||
translate:start(),
|
||||
acl:start(),
|
||||
ejabberd_ctl:init(),
|
||||
ejabberd_commands:init(),
|
||||
ejabberd_admin:start(),
|
||||
gen_mod:start(),
|
||||
ejabberd_config:start(),
|
||||
set_loglevel_from_config(),
|
||||
acl:start(),
|
||||
shaper:start(),
|
||||
connect_nodes(),
|
||||
Sup = ejabberd_sup:start_link(),
|
||||
ejabberd_rdbms:start(),
|
||||
@ -119,7 +121,7 @@ db_init() ->
|
||||
start_modules() ->
|
||||
lists:foreach(
|
||||
fun(Host) ->
|
||||
Modules = ejabberd_config:get_local_option(
|
||||
Modules = ejabberd_config:get_option(
|
||||
{modules, Host},
|
||||
fun(Mods) ->
|
||||
lists:map(
|
||||
@ -137,7 +139,7 @@ start_modules() ->
|
||||
stop_modules() ->
|
||||
lists:foreach(
|
||||
fun(Host) ->
|
||||
Modules = ejabberd_config:get_local_option(
|
||||
Modules = ejabberd_config:get_option(
|
||||
{modules, Host},
|
||||
fun(Mods) ->
|
||||
lists:map(
|
||||
@ -152,7 +154,7 @@ stop_modules() ->
|
||||
end, ?MYHOSTS).
|
||||
|
||||
connect_nodes() ->
|
||||
Nodes = ejabberd_config:get_local_option(
|
||||
Nodes = ejabberd_config:get_option(
|
||||
cluster_nodes,
|
||||
fun(Ns) ->
|
||||
true = lists:all(fun is_atom/1, Ns),
|
||||
@ -212,9 +214,17 @@ delete_pid_file() ->
|
||||
file:delete(PidFilename)
|
||||
end.
|
||||
|
||||
set_loglevel_from_config() ->
|
||||
Level = ejabberd_config:get_option(
|
||||
loglevel,
|
||||
fun(P) when P>=0, P=<5 -> P end,
|
||||
4),
|
||||
ejabberd_logger:set(Level).
|
||||
|
||||
start_apps() ->
|
||||
ejabberd:start_app(sasl),
|
||||
ejabberd:start_app(ssl),
|
||||
ejabberd:start_app(p1_yaml),
|
||||
ejabberd:start_app(p1_tls),
|
||||
ejabberd:start_app(p1_xml),
|
||||
ejabberd:start_app(p1_stringprep),
|
||||
|
@ -423,7 +423,7 @@ auth_modules() ->
|
||||
%% Return the list of authenticated modules for a given host
|
||||
auth_modules(Server) ->
|
||||
LServer = jlib:nameprep(Server),
|
||||
Methods = ejabberd_config:get_local_option(
|
||||
Methods = ejabberd_config:get_option(
|
||||
{auth_method, LServer},
|
||||
fun(V) when is_list(V) ->
|
||||
true = lists:all(fun is_atom/1, V),
|
||||
|
@ -104,7 +104,7 @@ is_login_anonymous_enabled(Host) ->
|
||||
%% Return the anonymous protocol to use: sasl_anon|login_anon|both
|
||||
%% defaults to login_anon
|
||||
anonymous_protocol(Host) ->
|
||||
ejabberd_config:get_local_option(
|
||||
ejabberd_config:get_option(
|
||||
{anonymous_protocol, Host},
|
||||
fun(sasl_anon) -> sasl_anon;
|
||||
(login_anon) -> login_anon;
|
||||
@ -115,7 +115,7 @@ anonymous_protocol(Host) ->
|
||||
%% Return true if multiple connections have been allowed in the config file
|
||||
%% defaults to false
|
||||
allow_multiple_connections(Host) ->
|
||||
ejabberd_config:get_local_option(
|
||||
ejabberd_config:get_option(
|
||||
{allow_multiple_connections, Host},
|
||||
fun(V) when is_boolean(V) -> V end,
|
||||
false).
|
||||
|
@ -48,7 +48,7 @@
|
||||
%%% API
|
||||
%%%----------------------------------------------------------------------
|
||||
start(Host) ->
|
||||
Cmd = ejabberd_config:get_local_option(
|
||||
Cmd = ejabberd_config:get_option(
|
||||
{extauth_program, Host},
|
||||
fun(V) ->
|
||||
binary_to_list(iolist_to_binary(V))
|
||||
@ -171,7 +171,7 @@ remove_user(User, Server, Password) ->
|
||||
|
||||
%% @spec (Host::string()) -> false | {true, CacheTime::integer()}
|
||||
get_cache_option(Host) ->
|
||||
case ejabberd_config:get_local_option(
|
||||
case ejabberd_config:get_option(
|
||||
{extauth_cache, Host},
|
||||
fun(I) when is_integer(I), I > 0 -> I end) of
|
||||
undefined -> false;
|
||||
|
@ -406,7 +406,7 @@ is_scrammed() ->
|
||||
|
||||
is_option_scram() ->
|
||||
scram ==
|
||||
ejabberd_config:get_local_option({auth_password_format, ?MYNAME},
|
||||
ejabberd_config:get_option({auth_password_format, ?MYNAME},
|
||||
fun(V) -> V end).
|
||||
|
||||
maybe_alert_password_scrammed_without_option() ->
|
||||
|
@ -369,8 +369,10 @@ parse_options(Host) ->
|
||||
{iolist_to_binary(U),
|
||||
iolist_to_binary(P)};
|
||||
({U}) ->
|
||||
{iolist_to_binary(U)};
|
||||
(U) ->
|
||||
{iolist_to_binary(U)}
|
||||
end, Us)
|
||||
end, lists:flatten(Us))
|
||||
end, [{<<"uid">>, <<"%u">>}]),
|
||||
UIDs = eldap_utils:uids_domain_subst(Host, UIDsTemp),
|
||||
SubFilter = eldap_utils:generate_subfilter(UIDs),
|
||||
|
@ -107,13 +107,13 @@ store_type() -> external.
|
||||
%% Internal functions
|
||||
%%====================================================================
|
||||
get_pam_service(Host) ->
|
||||
ejabberd_config:get_local_option(
|
||||
ejabberd_config:get_option(
|
||||
{pam_service, Host},
|
||||
fun iolist_to_binary/1,
|
||||
<<"ejabberd">>).
|
||||
|
||||
get_pam_userinfotype(Host) ->
|
||||
ejabberd_config:get_local_option(
|
||||
ejabberd_config:get_option(
|
||||
{pam_userinfotype, Host},
|
||||
fun(username) -> username;
|
||||
(jid) -> jid
|
||||
|
@ -47,7 +47,8 @@
|
||||
del_aux_field/2,
|
||||
get_subscription/2,
|
||||
broadcast/4,
|
||||
get_subscribed/1]).
|
||||
get_subscribed/1,
|
||||
transform_listen_option/2]).
|
||||
|
||||
%% gen_fsm callbacks
|
||||
-export([init/1,
|
||||
@ -233,11 +234,10 @@ init([{SockMod, Socket}, Opts]) ->
|
||||
{value, {_, XS}} -> XS;
|
||||
_ -> false
|
||||
end,
|
||||
Zlib = lists:member(zlib, Opts),
|
||||
StartTLS = lists:member(starttls, Opts),
|
||||
StartTLSRequired = lists:member(starttls_required,
|
||||
Opts),
|
||||
TLSEnabled = lists:member(tls, Opts),
|
||||
Zlib = proplists:get_bool(zlib, Opts),
|
||||
StartTLS = proplists:get_bool(starttls, Opts),
|
||||
StartTLSRequired = proplists:get_bool(starttls_required, Opts),
|
||||
TLSEnabled = proplists:get_bool(tls, Opts),
|
||||
TLS = StartTLS orelse
|
||||
StartTLSRequired orelse TLSEnabled,
|
||||
TLSOpts1 = lists:filter(fun ({certfile, _}) -> true;
|
||||
@ -682,7 +682,7 @@ wait_for_feature_request({xmlstreamelement, El},
|
||||
when TLS == true, TLSEnabled == false,
|
||||
SockMod == gen_tcp ->
|
||||
TLSOpts = case
|
||||
ejabberd_config:get_local_option(
|
||||
ejabberd_config:get_option(
|
||||
{domain_certfile, StateData#state.server},
|
||||
fun iolist_to_binary/1)
|
||||
of
|
||||
@ -876,7 +876,7 @@ resource_conflict_action(U, S, R) ->
|
||||
R)
|
||||
of
|
||||
true ->
|
||||
ejabberd_config:get_local_option(
|
||||
ejabberd_config:get_option(
|
||||
{resource_conflict, S},
|
||||
fun(setresource) -> setresource;
|
||||
(closeold) -> closeold;
|
||||
@ -2279,7 +2279,7 @@ fsm_limit_opts(Opts) ->
|
||||
case lists:keysearch(max_fsm_queue, 1, Opts) of
|
||||
{value, {_, N}} when is_integer(N) -> [{max_queue, N}];
|
||||
_ ->
|
||||
case ejabberd_config:get_local_option(
|
||||
case ejabberd_config:get_option(
|
||||
max_fsm_queue,
|
||||
fun(I) when is_integer(I), I > 0 -> I end) of
|
||||
undefined -> [];
|
||||
@ -2377,3 +2377,6 @@ pack_string(String, Pack) ->
|
||||
{value, PackedString} -> {PackedString, Pack};
|
||||
none -> {String, gb_trees:insert(String, String, Pack)}
|
||||
end.
|
||||
|
||||
transform_listen_option(Opt, Opts) ->
|
||||
[Opt|Opts].
|
||||
|
@ -34,7 +34,7 @@
|
||||
%% Get first c2s configuration limitations to apply it to other c2s
|
||||
%% connectors.
|
||||
get_c2s_limits() ->
|
||||
case ejabberd_config:get_local_option(listen, fun(V) -> V end) of
|
||||
case ejabberd_config:get_option(listen, fun(V) -> V end) of
|
||||
undefined -> [];
|
||||
C2SFirstListen ->
|
||||
case lists:keysearch(ejabberd_c2s, 2, C2SFirstListen) of
|
||||
|
@ -504,7 +504,7 @@ do_create_image(Key) ->
|
||||
end.
|
||||
|
||||
get_prog_name() ->
|
||||
case ejabberd_config:get_local_option(
|
||||
case ejabberd_config:get_option(
|
||||
captcha_cmd,
|
||||
fun(FileName) ->
|
||||
F = iolist_to_binary(FileName),
|
||||
@ -521,7 +521,7 @@ get_prog_name() ->
|
||||
end.
|
||||
|
||||
get_url(Str) ->
|
||||
CaptchaHost = ejabberd_config:get_local_option(
|
||||
CaptchaHost = ejabberd_config:get_option(
|
||||
captcha_host,
|
||||
fun iolist_to_binary/1,
|
||||
<<"">>),
|
||||
@ -549,7 +549,7 @@ get_transfer_protocol(PortString) ->
|
||||
get_captcha_transfer_protocol(PortListeners).
|
||||
|
||||
get_port_listeners(PortNumber) ->
|
||||
AllListeners = ejabberd_config:get_local_option(listen, fun(V) -> V end),
|
||||
AllListeners = ejabberd_config:get_option(listen, fun(V) -> V end),
|
||||
lists:filter(fun ({{Port, _Ip, _Netp}, _Module1,
|
||||
_Opts1})
|
||||
when Port == PortNumber ->
|
||||
@ -579,7 +579,7 @@ get_captcha_transfer_protocol([_ | Listeners]) ->
|
||||
|
||||
is_limited(undefined) -> false;
|
||||
is_limited(Limiter) ->
|
||||
case ejabberd_config:get_local_option(
|
||||
case ejabberd_config:get_option(
|
||||
captcha_limit,
|
||||
fun(I) when is_integer(I), I > 0 -> I end) of
|
||||
undefined -> false;
|
||||
|
@ -27,16 +27,16 @@
|
||||
-module(ejabberd_config).
|
||||
-author('alexey@process-one.net').
|
||||
|
||||
-export([start/0, load_file/1,
|
||||
-export([start/0, load_file/1, read_file/1,
|
||||
add_global_option/2, add_local_option/2,
|
||||
get_global_option/2, get_local_option/2,
|
||||
get_global_option/3, get_local_option/3,
|
||||
get_option/2, get_option/3, add_option/2]).
|
||||
-export([get_vh_by_auth_method/1]).
|
||||
-export([is_file_readable/1]).
|
||||
-export([get_version/0, get_myhosts/0, get_mylang/0]).
|
||||
-export([prepare_opt_val/4]).
|
||||
-export([convert_table_to_binary/5]).
|
||||
get_option/2, get_option/3, add_option/2,
|
||||
get_vh_by_auth_method/1, is_file_readable/1,
|
||||
get_version/0, get_myhosts/0, get_mylang/0,
|
||||
prepare_opt_val/4, convert_table_to_binary/5,
|
||||
transform_options/1, collect_options/1,
|
||||
convert_to_yaml/1, convert_to_yaml/2]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
@ -53,21 +53,29 @@
|
||||
|
||||
|
||||
start() ->
|
||||
case catch mnesia:table_info(local_config, storage_type) of
|
||||
disc_copies ->
|
||||
mnesia:delete_table(local_config);
|
||||
_ ->
|
||||
ok
|
||||
end,
|
||||
mnesia:create_table(local_config,
|
||||
[{disc_copies, [node()]},
|
||||
[{ram_copies, [node()]},
|
||||
{local_content, true},
|
||||
{attributes, record_info(fields, local_config)}]),
|
||||
mnesia:add_table_copy(local_config, node(), ram_copies),
|
||||
Config = get_ejabberd_config_path(),
|
||||
load_file(Config),
|
||||
State = read_file(Config),
|
||||
%% This start time is used by mod_last:
|
||||
add_option(node_start, now()),
|
||||
ok.
|
||||
{MegaSecs, Secs, _} = now(),
|
||||
UnixTime = MegaSecs*1000000 + Secs,
|
||||
State1 = set_option({node_start, global}, UnixTime, State),
|
||||
set_opts(State1).
|
||||
|
||||
%% @doc Get the filename of the ejabberd configuration file.
|
||||
%% The filename can be specified with: erl -config "/path/to/ejabberd.cfg".
|
||||
%% The filename can be specified with: erl -config "/path/to/ejabberd.yml".
|
||||
%% It can also be specified with the environtment variable EJABBERD_CONFIG_PATH.
|
||||
%% If not specified, the default value 'ejabberd.cfg' is assumed.
|
||||
%% If not specified, the default value 'ejabberd.yml' is assumed.
|
||||
%% @spec () -> string()
|
||||
get_ejabberd_config_path() ->
|
||||
case application:get_env(config) of
|
||||
@ -81,16 +89,59 @@ get_ejabberd_config_path() ->
|
||||
end
|
||||
end.
|
||||
|
||||
%% @doc Load the ejabberd configuration file.
|
||||
%% @doc Read the ejabberd configuration file.
|
||||
%% It also includes additional configuration files and replaces macros.
|
||||
%% This function will crash if finds some error in the configuration file.
|
||||
%% @spec (File::string()) -> ok
|
||||
load_file(File) ->
|
||||
Terms = get_plain_terms_file(File),
|
||||
%% @spec (File::string()) -> #state{}.
|
||||
read_file(File) ->
|
||||
read_file(File, [{replace_macros, true},
|
||||
{include_files, true}]).
|
||||
|
||||
read_file(File, Opts) ->
|
||||
Terms1 = get_plain_terms_file(File, Opts),
|
||||
Terms_macros = case proplists:get_bool(replace_macros, Opts) of
|
||||
true -> replace_macros(Terms1);
|
||||
false -> Terms1
|
||||
end,
|
||||
Terms = transform_terms(Terms_macros),
|
||||
State = lists:foldl(fun search_hosts/2, #state{}, Terms),
|
||||
Terms_macros = replace_macros(Terms),
|
||||
Res = lists:foldl(fun process_term/2, State, Terms_macros),
|
||||
set_opts(Res).
|
||||
{Head, Tail} = lists:partition(
|
||||
fun({host_config, _}) -> false;
|
||||
({append_host_config, _}) -> false;
|
||||
(_) -> true
|
||||
end, Terms),
|
||||
State1 = lists:foldl(fun process_term/2, State, Head ++ Tail),
|
||||
State1#state{opts = compact(State1#state.opts)}.
|
||||
|
||||
-spec load_file(string()) -> ok.
|
||||
|
||||
load_file(File) ->
|
||||
State = read_file(File),
|
||||
set_opts(State).
|
||||
|
||||
-spec convert_to_yaml(file:filename()) -> ok | {error, any()}.
|
||||
|
||||
convert_to_yaml(File) ->
|
||||
convert_to_yaml(File, stdout).
|
||||
|
||||
-spec convert_to_yaml(file:filename(),
|
||||
stdout | file:filename()) -> ok | {error, any()}.
|
||||
|
||||
convert_to_yaml(File, Output) ->
|
||||
State = read_file(File, [{include_files, false}]),
|
||||
Opts = [{K, V} || #local_config{key = K, value = V} <- State#state.opts],
|
||||
{GOpts, HOpts} = split_by_hosts(Opts),
|
||||
NewOpts = GOpts ++ lists:map(
|
||||
fun({Host, Opts1}) ->
|
||||
{host_config, [{Host, Opts1}]}
|
||||
end, HOpts),
|
||||
Data = p1_yaml:encode(lists:reverse(NewOpts)),
|
||||
case Output of
|
||||
stdout ->
|
||||
io:format("~s~n", [Data]);
|
||||
FileName ->
|
||||
file:write_file(FileName, Data)
|
||||
end.
|
||||
|
||||
%% @doc Read an ejabberd configuration file and return the terms.
|
||||
%% Input is an absolute or relative path to an ejabberd config file.
|
||||
@ -99,22 +150,47 @@ load_file(File) ->
|
||||
%% and the terms in those files were included.
|
||||
%% @spec(string()) -> [term()]
|
||||
%% @spec(iolist()) -> [term()]
|
||||
get_plain_terms_file(File) when is_binary(File) ->
|
||||
get_plain_terms_file(binary_to_list(File));
|
||||
get_plain_terms_file(File1) ->
|
||||
get_plain_terms_file(File) ->
|
||||
get_plain_terms_file(File, [{include_files, true}]).
|
||||
|
||||
get_plain_terms_file(File, Opts) when is_binary(File) ->
|
||||
get_plain_terms_file(binary_to_list(File), Opts);
|
||||
get_plain_terms_file(File1, Opts) ->
|
||||
File = get_absolute_path(File1),
|
||||
case file:consult(File) of
|
||||
case consult(File) of
|
||||
{ok, Terms} ->
|
||||
BinTerms = strings_to_binary(Terms),
|
||||
include_config_files(BinTerms);
|
||||
{error, {LineNumber, erl_parse, _ParseMessage} = Reason} ->
|
||||
ExitText = describe_config_problem(File, Reason, LineNumber),
|
||||
?ERROR_MSG(ExitText, []),
|
||||
exit_or_halt(ExitText);
|
||||
case proplists:get_bool(include_files, Opts) of
|
||||
true ->
|
||||
include_config_files(BinTerms);
|
||||
false ->
|
||||
BinTerms
|
||||
end;
|
||||
{error, Reason} ->
|
||||
ExitText = describe_config_problem(File, Reason),
|
||||
?ERROR_MSG(ExitText, []),
|
||||
exit_or_halt(ExitText)
|
||||
?ERROR_MSG(Reason, []),
|
||||
exit_or_halt(Reason)
|
||||
end.
|
||||
|
||||
consult(File) ->
|
||||
case filename:extension(File) of
|
||||
".yml" ->
|
||||
case p1_yaml:decode_from_file(File, [plain_as_atom]) of
|
||||
{ok, []} ->
|
||||
{ok, []};
|
||||
{ok, [Document|_]} ->
|
||||
{ok, Document};
|
||||
{error, Err} ->
|
||||
{error, p1_yaml:format_error(Err)}
|
||||
end;
|
||||
_ ->
|
||||
case file:consult(File) of
|
||||
{ok, Terms} ->
|
||||
{ok, Terms};
|
||||
{error, {LineNumber, erl_parse, _ParseMessage} = Reason} ->
|
||||
{error, describe_config_problem(File, Reason, LineNumber)};
|
||||
{error, Reason} ->
|
||||
{error, describe_config_problem(File, Reason)}
|
||||
end
|
||||
end.
|
||||
|
||||
%% @doc Convert configuration filename to absolute path.
|
||||
@ -158,7 +234,7 @@ search_hosts(Term, State) ->
|
||||
|
||||
add_hosts_to_option(Hosts, State) ->
|
||||
PrepHosts = normalize_hosts(Hosts),
|
||||
add_option(hosts, PrepHosts, State#state{hosts = PrepHosts}).
|
||||
set_option({hosts, global}, PrepHosts, State#state{hosts = PrepHosts}).
|
||||
|
||||
normalize_hosts(Hosts) ->
|
||||
normalize_hosts(Hosts,[]).
|
||||
@ -232,21 +308,37 @@ exit_or_halt(ExitText) ->
|
||||
%% @doc Include additional configuration files in the list of terms.
|
||||
%% @spec ([term()]) -> [term()]
|
||||
include_config_files(Terms) ->
|
||||
include_config_files(Terms, []).
|
||||
{FileOpts, Terms1} =
|
||||
lists:mapfoldl(
|
||||
fun({include_config_file, _} = T, Ts) ->
|
||||
{[transform_include_option(T)], Ts};
|
||||
({include_config_file, _, _} = T, Ts) ->
|
||||
{[transform_include_option(T)], Ts};
|
||||
(T, Ts) ->
|
||||
{[], [T|Ts]}
|
||||
end, [], Terms),
|
||||
Terms2 = lists:flatmap(
|
||||
fun({File, Opts}) ->
|
||||
include_config_file(File, Opts)
|
||||
end, lists:flatten(FileOpts)),
|
||||
Terms1 ++ Terms2.
|
||||
|
||||
include_config_files([], Res) ->
|
||||
Res;
|
||||
include_config_files([{include_config_file, Filename} | Terms], Res) ->
|
||||
include_config_files([{include_config_file, Filename, []} | Terms], Res);
|
||||
include_config_files([{include_config_file, Filename, Options} | Terms], Res) ->
|
||||
transform_include_option({include_config_file, File}) when is_list(File) ->
|
||||
case is_string(File) of
|
||||
true -> {File, []};
|
||||
false -> File
|
||||
end;
|
||||
transform_include_option({include_config_file, Filename}) ->
|
||||
{Filename, []};
|
||||
transform_include_option({include_config_file, Filename, Options}) ->
|
||||
{Filename, Options}.
|
||||
|
||||
include_config_file(Filename, Options) ->
|
||||
Included_terms = get_plain_terms_file(Filename),
|
||||
Disallow = proplists:get_value(disallow, Options, []),
|
||||
Included_terms2 = delete_disallowed(Disallow, Included_terms),
|
||||
Allow_only = proplists:get_value(allow_only, Options, all),
|
||||
Included_terms3 = keep_only_allowed(Allow_only, Included_terms2),
|
||||
include_config_files(Terms, Res ++ Included_terms3);
|
||||
include_config_files([Term | Terms], Res) ->
|
||||
include_config_files(Terms, Res ++ [Term]).
|
||||
keep_only_allowed(Allow_only, Included_terms2).
|
||||
|
||||
%% @doc Filter from the list of terms the disallowed.
|
||||
%% Returns a sublist of Terms without the ones which first element is
|
||||
@ -308,12 +400,19 @@ split_terms_macros(Terms) ->
|
||||
fun(Term, {TOs, Ms}) ->
|
||||
case Term of
|
||||
{define_macro, Key, Value} ->
|
||||
case is_atom(Key) and is_all_uppercase(Key) of
|
||||
case is_correct_macro({Key, Value}) of
|
||||
true ->
|
||||
{TOs, Ms++[{Key, Value}]};
|
||||
false ->
|
||||
exit({macro_not_properly_defined, Term})
|
||||
end;
|
||||
{define_macro, KeyVals} ->
|
||||
case lists:all(fun is_correct_macro/1, KeyVals) of
|
||||
true ->
|
||||
{TOs, Ms ++ KeyVals};
|
||||
false ->
|
||||
exit({macros_not_properly_defined, Term})
|
||||
end;
|
||||
Term ->
|
||||
{TOs ++ [Term], Ms}
|
||||
end
|
||||
@ -321,6 +420,11 @@ split_terms_macros(Terms) ->
|
||||
{[], []},
|
||||
Terms).
|
||||
|
||||
is_correct_macro({Key, _Val}) ->
|
||||
is_atom(Key) and is_all_uppercase(Key);
|
||||
is_correct_macro(_) ->
|
||||
false.
|
||||
|
||||
%% @doc Recursively replace in Terms macro usages with the defined value.
|
||||
%% @spec (Terms, Macros) -> Terms
|
||||
%% Terms = [term()]
|
||||
@ -328,7 +432,9 @@ split_terms_macros(Terms) ->
|
||||
replace([], _) ->
|
||||
[];
|
||||
replace([Term|Terms], Macros) ->
|
||||
[replace_term(Term, Macros) | replace(Terms, Macros)].
|
||||
[replace_term(Term, Macros) | replace(Terms, Macros)];
|
||||
replace(Term, Macros) ->
|
||||
replace_term(Term, Macros).
|
||||
|
||||
replace_term(Key, Macros) when is_atom(Key) ->
|
||||
case is_all_uppercase(Key) of
|
||||
@ -362,121 +468,65 @@ is_all_uppercase(Atom) ->
|
||||
|
||||
process_term(Term, State) ->
|
||||
case Term of
|
||||
override_global ->
|
||||
State#state{override_global = true};
|
||||
override_local ->
|
||||
State#state{override_local = true};
|
||||
override_acls ->
|
||||
State#state{override_acls = true};
|
||||
{host_config, Host, Terms} ->
|
||||
lists:foldl(fun(T, S) -> process_host_term(T, Host, S) end,
|
||||
State, Terms);
|
||||
{listen, Listeners} ->
|
||||
Listeners2 =
|
||||
lists:map(
|
||||
fun({PortIP, Module, Opts}) ->
|
||||
{Port, IPT, _, _, Proto, OptsClean} =
|
||||
ejabberd_listener:parse_listener_portip(PortIP, Opts),
|
||||
{{Port, IPT, Proto}, Module, OptsClean}
|
||||
end,
|
||||
Listeners),
|
||||
add_option(listen, Listeners2, State);
|
||||
{s2s_certfile, CertFile} ->
|
||||
CertFileS = binary_to_list(CertFile),
|
||||
case ejabberd_config:is_file_readable(CertFileS) of
|
||||
true -> add_option(s2s_certfile, CertFile, State);
|
||||
false ->
|
||||
ErrorText = "There is a problem in the configuration: "
|
||||
"the specified file is not readable: ",
|
||||
throw({error, ErrorText ++ CertFileS})
|
||||
end;
|
||||
{domain_certfile, Domain, CertFile} ->
|
||||
CertFileS = binary_to_list(CertFile),
|
||||
case ejabberd_config:is_file_readable(CertFileS) of
|
||||
true -> add_option({domain_certfile, Domain}, CertFile, State);
|
||||
false ->
|
||||
ErrorText = "There is a problem in the configuration: "
|
||||
"the specified file is not readable: ",
|
||||
throw({error, ErrorText ++ CertFileS})
|
||||
end;
|
||||
{loglevel, Loglevel} ->
|
||||
ejabberd_logger:set(Loglevel),
|
||||
State;
|
||||
{host_config, HostTerms} ->
|
||||
lists:foldl(
|
||||
fun({Host, Terms}, AccState) ->
|
||||
lists:foldl(fun(T, S) ->
|
||||
process_host_term(T, Host, S, set)
|
||||
end, AccState, Terms)
|
||||
end, State, HostTerms);
|
||||
{append_host_config, HostTerms} ->
|
||||
lists:foldl(
|
||||
fun({Host, Terms}, AccState) ->
|
||||
lists:foldl(fun(T, S) ->
|
||||
process_host_term(T, Host, S, append)
|
||||
end, AccState, Terms)
|
||||
end, State, HostTerms);
|
||||
_ ->
|
||||
lists:foldl(fun(Host, S) -> process_host_term(Term, Host, S) end,
|
||||
State, [global|State#state.hosts])
|
||||
process_host_term(Term, global, State, set)
|
||||
end.
|
||||
|
||||
process_host_term(Term, Host, State) ->
|
||||
process_host_term(Term, Host, State, Action) ->
|
||||
case Term of
|
||||
{acl, ACLName, ACLData} ->
|
||||
State#state{opts =
|
||||
[acl:to_record(Host, ACLName, ACLData) | State#state.opts]};
|
||||
{access, RuleName, Rules} ->
|
||||
add_option({access, RuleName, Host}, Rules, State);
|
||||
{shaper, Name, Data} ->
|
||||
add_option({shaper, Name, Host}, Data, State);
|
||||
{modules, Modules} ->
|
||||
add_option({modules, Host}, replace_modules(Modules), State);
|
||||
{modules, Modules} when Action == set ->
|
||||
set_option({modules, Host}, replace_modules(Modules), State);
|
||||
{modules, Modules} when Action == append ->
|
||||
append_option({modules, Host}, replace_modules(Modules), State);
|
||||
{host, _} ->
|
||||
State;
|
||||
{hosts, _} ->
|
||||
State;
|
||||
{Opt, Val} ->
|
||||
add_option({Opt, Host}, Val, State)
|
||||
{Opt, Val} when Action == set ->
|
||||
set_option({Opt, Host}, Val, State);
|
||||
{Opt, Val} when Action == append ->
|
||||
append_option({Opt, Host}, Val, State);
|
||||
Opt ->
|
||||
?WARNING_MSG("Ignore invalid (outdated?) option ~p", [Opt]),
|
||||
State
|
||||
end.
|
||||
|
||||
add_option(Opt, Val, State) when is_atom(Opt) ->
|
||||
add_option({Opt, global}, Val, State);
|
||||
add_option(Opt, Val, State) ->
|
||||
case Opt of
|
||||
{{add, OptName}, Host} ->
|
||||
State#state{opts = compact({OptName, Host}, Val,
|
||||
State#state.opts, [])};
|
||||
_ ->
|
||||
State#state{opts = [#local_config{key = Opt, value = Val} |
|
||||
State#state.opts]}
|
||||
end.
|
||||
|
||||
compact({OptName, Host} = Opt, Val, [], Os) ->
|
||||
?WARNING_MSG("The option '~p' is defined for the host ~p using host_config "
|
||||
"before the global '~p' option. This host_config option may get overwritten.", [OptName, Host, OptName]),
|
||||
[#local_config{key = Opt, value = Val}] ++ Os;
|
||||
%% Traverse the list of the options already parsed
|
||||
compact(Opt, Val, [O | Os1], Os2) ->
|
||||
case catch O#local_config.key of
|
||||
%% If the key of a local_config matches the Opt that wants to be added
|
||||
Opt ->
|
||||
%% Then prepend the new value to the list of old values
|
||||
Os2 ++ [#local_config{key = Opt,
|
||||
value = Val++O#local_config.value}
|
||||
] ++ Os1;
|
||||
_ ->
|
||||
compact(Opt, Val, Os1, Os2++[O])
|
||||
end.
|
||||
set_option(Opt, Val, State) ->
|
||||
State#state{opts = [#local_config{key = Opt, value = Val} |
|
||||
State#state.opts]}.
|
||||
|
||||
append_option({Opt, Host}, Val, State) ->
|
||||
GlobalVals = lists:flatmap(
|
||||
fun(#local_config{key = {O, global}, value = V})
|
||||
when O == Opt ->
|
||||
if is_list(V) -> V;
|
||||
true -> [V]
|
||||
end;
|
||||
(_) ->
|
||||
[]
|
||||
end, State#state.opts),
|
||||
NewVal = if is_list(Val) -> Val ++ GlobalVals;
|
||||
true -> [Val|GlobalVals]
|
||||
end,
|
||||
set_option({Opt, Host}, NewVal, State).
|
||||
|
||||
set_opts(State) ->
|
||||
Opts = lists:reverse(State#state.opts),
|
||||
Opts = State#state.opts,
|
||||
F = fun() ->
|
||||
if
|
||||
State#state.override_local ->
|
||||
Ksl = mnesia:all_keys(local_config),
|
||||
lists:foreach(fun(K) ->
|
||||
mnesia:delete({local_config, K})
|
||||
end, Ksl);
|
||||
true ->
|
||||
ok
|
||||
end,
|
||||
if
|
||||
State#state.override_acls ->
|
||||
Ksa = mnesia:all_keys(acl),
|
||||
lists:foreach(fun(K) ->
|
||||
mnesia:delete({acl, K})
|
||||
end, Ksa);
|
||||
true ->
|
||||
ok
|
||||
end,
|
||||
lists:foreach(fun(R) ->
|
||||
mnesia:write(R)
|
||||
end, Opts)
|
||||
@ -565,11 +615,22 @@ get_option(Opt, F) ->
|
||||
get_option(Opt, F, Default) when is_atom(Opt) ->
|
||||
get_option({Opt, global}, F, Default);
|
||||
get_option(Opt, F, Default) ->
|
||||
case Opt of
|
||||
{O, global} when is_atom(O) -> ok;
|
||||
{O, H} when is_atom(O), is_binary(H) -> ok;
|
||||
_ -> ?WARNING_MSG("Option ~p has invalid (outdated?) format. "
|
||||
"This is likely a bug", [Opt])
|
||||
end,
|
||||
case ets:lookup(local_config, Opt) of
|
||||
[#local_config{value = Val}] ->
|
||||
prepare_opt_val(Opt, Val, F, Default);
|
||||
_ ->
|
||||
Default
|
||||
_ ->
|
||||
case Opt of
|
||||
{Key, Host} when Host /= global ->
|
||||
get_option({Key, global}, F, Default);
|
||||
_ ->
|
||||
Default
|
||||
end
|
||||
end.
|
||||
|
||||
-spec get_vh_by_auth_method(atom()) -> [binary()].
|
||||
@ -632,14 +693,14 @@ replace_modules(Modules) ->
|
||||
emit_deprecation_warning(Module, NewModule, DBType),
|
||||
NewOpts = [{db_type, DBType} |
|
||||
lists:keydelete(db_type, 1, Opts)],
|
||||
{NewModule, NewOpts};
|
||||
{NewModule, transform_module_options(Module, NewOpts)};
|
||||
NewModule ->
|
||||
if Module /= NewModule ->
|
||||
emit_deprecation_warning(Module, NewModule);
|
||||
true ->
|
||||
ok
|
||||
end,
|
||||
{NewModule, Opts}
|
||||
{NewModule, transform_module_options(Module, Opts)}
|
||||
end
|
||||
end, Modules).
|
||||
|
||||
@ -695,6 +756,142 @@ format_term(S) when is_list(S), S /= [] ->
|
||||
format_term(T) ->
|
||||
io_lib:format("~p", [binary_to_strings(T)]).
|
||||
|
||||
transform_terms(Terms) ->
|
||||
%% We could check all ejabberd beams, but this
|
||||
%% slows down start-up procedure :(
|
||||
Mods = [mod_register,
|
||||
mod_last,
|
||||
ejabberd_s2s,
|
||||
ejabberd_listener,
|
||||
ejabberd_odbc_sup,
|
||||
shaper,
|
||||
ejabberd_s2s_out,
|
||||
acl,
|
||||
ejabberd_config],
|
||||
collect_options(transform_terms(Mods, Terms)).
|
||||
|
||||
transform_terms([Mod|Mods], Terms) ->
|
||||
case catch Mod:transform_options(Terms) of
|
||||
{'EXIT', _} = Err ->
|
||||
?ERROR_MSG("Failed to transform terms by ~p: ~p", [Mod, Err]),
|
||||
transform_terms(Mods, Terms);
|
||||
NewTerms ->
|
||||
transform_terms(Mods, NewTerms)
|
||||
end;
|
||||
transform_terms([], NewTerms) ->
|
||||
NewTerms.
|
||||
|
||||
transform_module_options(Module, Opts) ->
|
||||
Opts1 = gen_iq_handler:transform_module_options(Opts),
|
||||
try
|
||||
Module:transform_module_options(Opts1)
|
||||
catch error:undef ->
|
||||
Opts1
|
||||
end.
|
||||
|
||||
compact(Cfg) ->
|
||||
Opts = [{K, V} || #local_config{key = K, value = V} <- Cfg],
|
||||
{GOpts, HOpts} = split_by_hosts(Opts),
|
||||
[#local_config{key = {O, global}, value = V} || {O, V} <- GOpts] ++
|
||||
lists:flatmap(
|
||||
fun({Host, OptVal}) ->
|
||||
case lists:member(OptVal, GOpts) of
|
||||
true ->
|
||||
[];
|
||||
false ->
|
||||
[#local_config{key = {Opt, Host}, value = Val}
|
||||
|| {Opt, Val} <- OptVal]
|
||||
end
|
||||
end, lists:flatten(HOpts)).
|
||||
|
||||
split_by_hosts(Opts) ->
|
||||
Opts1 = orddict:to_list(
|
||||
lists:foldl(
|
||||
fun({{Opt, Host}, Val}, D) ->
|
||||
orddict:append(Host, {Opt, Val}, D)
|
||||
end, orddict:new(), Opts)),
|
||||
case lists:keytake(global, 1, Opts1) of
|
||||
{value, {global, GlobalOpts}, HostOpts} ->
|
||||
{GlobalOpts, HostOpts};
|
||||
_ ->
|
||||
{[], Opts1}
|
||||
end.
|
||||
|
||||
collect_options(Opts) ->
|
||||
{D, InvalidOpts} =
|
||||
lists:foldl(
|
||||
fun({K, V}, {D, Os}) when is_list(V) ->
|
||||
{orddict:append_list(K, V, D), Os};
|
||||
({K, V}, {D, Os}) ->
|
||||
{orddict:store(K, V, D), Os};
|
||||
(Opt, {D, Os}) ->
|
||||
{D, [Opt|Os]}
|
||||
end, {orddict:new(), []}, Opts),
|
||||
InvalidOpts ++ orddict:to_list(D).
|
||||
|
||||
transform_options(Opts) ->
|
||||
Opts1 = lists:foldl(fun transform_options/2, [], Opts),
|
||||
{HOpts, Opts2} = lists:mapfoldl(
|
||||
fun({host_config, O}, Os) ->
|
||||
{[O], Os};
|
||||
(O, Os) ->
|
||||
{[], [O|Os]}
|
||||
end, [], Opts1),
|
||||
{AHOpts, Opts3} = lists:mapfoldl(
|
||||
fun({append_host_config, O}, Os) ->
|
||||
{[O], Os};
|
||||
(O, Os) ->
|
||||
{[], [O|Os]}
|
||||
end, [], Opts2),
|
||||
HOpts1 = case collect_options(lists:flatten(HOpts)) of
|
||||
[] ->
|
||||
[];
|
||||
HOs ->
|
||||
[{host_config,
|
||||
[{H, transform_terms(O)} || {H, O} <- HOs]}]
|
||||
end,
|
||||
AHOpts1 = case collect_options(lists:flatten(AHOpts)) of
|
||||
[] ->
|
||||
[];
|
||||
AHOs ->
|
||||
[{append_host_config,
|
||||
[{H, transform_terms(O)} || {H, O} <- AHOs]}]
|
||||
end,
|
||||
HOpts1 ++ AHOpts1 ++ Opts3.
|
||||
|
||||
transform_options({domain_certfile, Domain, CertFile}, Opts) ->
|
||||
?WARNING_MSG("Option 'domain_certfile' now should be defined "
|
||||
"per virtual host or globally. The old format is "
|
||||
"still supported but it is better to fix your config", []),
|
||||
[{host_config, [{Domain, [{domain_certfile, CertFile}]}]}|Opts];
|
||||
transform_options(Opt, Opts) when Opt == override_global;
|
||||
Opt == override_local;
|
||||
Opt == override_acls ->
|
||||
?WARNING_MSG("Ignoring '~s' option which has no effect anymore", [Opt]),
|
||||
Opts;
|
||||
transform_options({host_config, Host, HOpts}, Opts) ->
|
||||
{AddOpts, HOpts1} =
|
||||
lists:mapfoldl(
|
||||
fun({{add, Opt}, Val}, Os) ->
|
||||
?WARNING_MSG("Option 'add' is deprecated. "
|
||||
"The option is still supported "
|
||||
"but it is better to fix your config: "
|
||||
"use 'append_host_config' instead.", []),
|
||||
{[{Opt, Val}], Os};
|
||||
(O, Os) ->
|
||||
{[], [O|Os]}
|
||||
end, [], HOpts),
|
||||
[{append_host_config, [{Host, lists:flatten(AddOpts)}]},
|
||||
{host_config, [{Host, HOpts1}]}|Opts];
|
||||
transform_options({define_macro, Macro, Val}, Opts) ->
|
||||
[{define_macro, [{Macro, Val}]}|Opts];
|
||||
transform_options({include_config_file, _} = Opt, Opts) ->
|
||||
[{include_config_file, [transform_include_option(Opt)]} | Opts];
|
||||
transform_options({include_config_file, _, _} = Opt, Opts) ->
|
||||
[{include_config_file, [transform_include_option(Opt)]} | Opts];
|
||||
transform_options(Opt, Opts) ->
|
||||
[Opt|Opts].
|
||||
|
||||
-spec convert_table_to_binary(atom(), [atom()], atom(),
|
||||
fun(), fun()) -> ok.
|
||||
|
||||
|
@ -237,7 +237,7 @@ process2(Args, Auth, AccessCommands) ->
|
||||
end.
|
||||
|
||||
get_accesscommands() ->
|
||||
ejabberd_config:get_local_option(ejabberdctl_access_commands,
|
||||
ejabberd_config:get_option(ejabberdctl_access_commands,
|
||||
fun(V) when is_list(V) -> V end, []).
|
||||
|
||||
%%-----------------------------
|
||||
|
@ -280,7 +280,7 @@ code_change(_OldVsn, State, _Extra) -> {ok, State}.
|
||||
%%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
check_starttls(SockMod, Socket, Receiver, Opts) ->
|
||||
TLSEnabled = lists:member(tls, Opts),
|
||||
TLSEnabled = proplists:get_bool(tls, Opts),
|
||||
TLSOpts = lists:filter(fun({certfile, _}) -> true;
|
||||
(_) -> false
|
||||
end, Opts),
|
||||
@ -292,4 +292,3 @@ check_starttls(SockMod, Socket, Receiver, Opts) ->
|
||||
true ->
|
||||
{SockMod, Socket}
|
||||
end.
|
||||
|
||||
|
@ -30,7 +30,8 @@
|
||||
|
||||
%% External exports
|
||||
-export([start/2, start_link/2, become_controller/1,
|
||||
socket_type/0, receive_headers/1, url_encode/1]).
|
||||
socket_type/0, receive_headers/1, url_encode/1,
|
||||
transform_listen_option/2]).
|
||||
|
||||
%% Callbacks
|
||||
-export([init/2]).
|
||||
@ -91,7 +92,7 @@ start_link(SockData, Opts) ->
|
||||
[SockData, Opts])}.
|
||||
|
||||
init({SockMod, Socket}, Opts) ->
|
||||
TLSEnabled = lists:member(tls, Opts),
|
||||
TLSEnabled = proplists:get_bool(tls, Opts),
|
||||
TLSOpts1 = lists:filter(fun ({certfile, _}) -> true;
|
||||
(_) -> false
|
||||
end,
|
||||
@ -133,12 +134,13 @@ init({SockMod, Socket}, Opts) ->
|
||||
true -> [{[<<"http-poll">>], ejabberd_http_poll}];
|
||||
false -> []
|
||||
end,
|
||||
DefinedHandlers = case lists:keysearch(request_handlers,
|
||||
1, Opts)
|
||||
of
|
||||
{value, {request_handlers, H}} -> H;
|
||||
false -> []
|
||||
end,
|
||||
DefinedHandlers = gen_mod:get_opt(
|
||||
request_handlers, Opts,
|
||||
fun(Hs) ->
|
||||
[{str:tokens(
|
||||
iolist_to_binary(Path), <<"/">>),
|
||||
Mod} || {Path, Mod} <- Hs]
|
||||
end, []),
|
||||
RequestHandlers = DefinedHandlers ++ Captcha ++ Register ++
|
||||
Admin ++ Bind ++ Poll,
|
||||
?DEBUG("S: ~p~n", [RequestHandlers]),
|
||||
@ -484,7 +486,7 @@ analyze_ip_xff(IP, [], _Host) -> IP;
|
||||
analyze_ip_xff({IPLast, Port}, XFF, Host) ->
|
||||
[ClientIP | ProxiesIPs] = str:tokens(XFF, <<", ">>) ++
|
||||
[jlib:ip_to_list(IPLast)],
|
||||
TrustedProxies = ejabberd_config:get_local_option(
|
||||
TrustedProxies = ejabberd_config:get_option(
|
||||
{trusted_proxies, Host},
|
||||
fun(TPs) ->
|
||||
[iolist_to_binary(TP) || TP <- TPs]
|
||||
@ -834,3 +836,25 @@ normalize_path([_Parent, <<"..">>|Path], Norm) ->
|
||||
normalize_path(Path, Norm);
|
||||
normalize_path([Part | Path], Norm) ->
|
||||
normalize_path(Path, [Part|Norm]).
|
||||
|
||||
transform_listen_option(captcha, Opts) ->
|
||||
[{captcha, true}|Opts];
|
||||
transform_listen_option(register, Opts) ->
|
||||
[{register, true}|Opts];
|
||||
transform_listen_option(web_admin, Opts) ->
|
||||
[{web_admin, true}|Opts];
|
||||
transform_listen_option(http_bind, Opts) ->
|
||||
[{http_bind, true}|Opts];
|
||||
transform_listen_option(http_poll, Opts) ->
|
||||
[{http_poll, true}|Opts];
|
||||
transform_listen_option({request_handlers, Hs}, Opts) ->
|
||||
Hs1 = lists:map(
|
||||
fun({PList, Mod}) when is_list(PList) ->
|
||||
Path = iolist_to_binary([[$/, P] || P <- PList]),
|
||||
{Path, Mod};
|
||||
(Opt) ->
|
||||
Opt
|
||||
end, Hs),
|
||||
[{request_handlers, Hs1} | Opts];
|
||||
transform_listen_option(Opt, Opts) ->
|
||||
[Opt|Opts].
|
||||
|
@ -205,7 +205,7 @@ get_human_html_xmlel() ->
|
||||
init([ID, Key, IP]) ->
|
||||
?INFO_MSG("started: ~p", [{ID, Key, IP}]),
|
||||
Opts = ejabberd_c2s_config:get_c2s_limits(),
|
||||
HTTPPollTimeout = ejabberd_config:get_local_option(
|
||||
HTTPPollTimeout = ejabberd_config:get_option(
|
||||
{http_poll_timeout, ?MYNAME},
|
||||
fun(I) when is_integer(I), I>0 -> I end,
|
||||
?HTTP_POLL_TIMEOUT) * 1000,
|
||||
|
@ -36,7 +36,8 @@
|
||||
parse_listener_portip/2,
|
||||
add_listener/3,
|
||||
delete_listener/2,
|
||||
validate_cfg/1
|
||||
transform_options/1,
|
||||
validate_cfg/1
|
||||
]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
@ -55,7 +56,7 @@ init(_) ->
|
||||
{ok, {{one_for_one, 10, 1}, []}}.
|
||||
|
||||
bind_tcp_ports() ->
|
||||
case ejabberd_config:get_local_option(listen, fun validate_cfg/1) of
|
||||
case ejabberd_config:get_option(listen, fun validate_cfg/1) of
|
||||
undefined ->
|
||||
ignore;
|
||||
Ls ->
|
||||
@ -88,7 +89,7 @@ bind_tcp_port(PortIP, Module, RawOpts) ->
|
||||
end.
|
||||
|
||||
start_listeners() ->
|
||||
case ejabberd_config:get_local_option(listen, fun validate_cfg/1) of
|
||||
case ejabberd_config:get_option(listen, fun validate_cfg/1) of
|
||||
undefined ->
|
||||
ignore;
|
||||
Ls ->
|
||||
@ -267,7 +268,7 @@ strip_ip_option(Opts) ->
|
||||
Opts),
|
||||
case IPL of
|
||||
%% Only the first ip option is considered
|
||||
[{ip, T1} | _] when is_tuple(T1) ->
|
||||
[{ip, T1} | _] ->
|
||||
{T1, OptsNoIP};
|
||||
[] ->
|
||||
{no_ip_option, OptsNoIP}
|
||||
@ -364,7 +365,7 @@ start_listener_sup(Port, Module, Opts) ->
|
||||
supervisor:start_child(ejabberd_listeners, ChildSpec).
|
||||
|
||||
stop_listeners() ->
|
||||
Ports = ejabberd_config:get_local_option(listen, fun validate_cfg/1),
|
||||
Ports = ejabberd_config:get_option(listen, fun validate_cfg/1),
|
||||
lists:foreach(
|
||||
fun({PortIpNetp, Module, _Opts}) ->
|
||||
delete_listener(PortIpNetp, Module)
|
||||
@ -397,7 +398,7 @@ add_listener(PortIP, Module, Opts) ->
|
||||
PortIP1 = {Port, IPT, Proto},
|
||||
case start_listener(PortIP1, Module, Opts) of
|
||||
{ok, _Pid} ->
|
||||
Ports = case ejabberd_config:get_local_option(
|
||||
Ports = case ejabberd_config:get_option(
|
||||
listen, fun validate_cfg/1) of
|
||||
undefined ->
|
||||
[];
|
||||
@ -406,7 +407,8 @@ add_listener(PortIP, Module, Opts) ->
|
||||
end,
|
||||
Ports1 = lists:keydelete(PortIP1, 1, Ports),
|
||||
Ports2 = [{PortIP1, Module, Opts} | Ports1],
|
||||
ejabberd_config:add_local_option(listen, Ports2),
|
||||
Ports3 = lists:map(fun transform_option/1, Ports2),
|
||||
ejabberd_config:add_option(listen, Ports3),
|
||||
ok;
|
||||
{error, {already_started, _Pid}} ->
|
||||
{error, {already_started, PortIP}};
|
||||
@ -428,7 +430,7 @@ delete_listener(PortIP, Module) ->
|
||||
delete_listener(PortIP, Module, Opts) ->
|
||||
{Port, IPT, _, _, Proto, _} = parse_listener_portip(PortIP, Opts),
|
||||
PortIP1 = {Port, IPT, Proto},
|
||||
Ports = case ejabberd_config:get_local_option(
|
||||
Ports = case ejabberd_config:get_option(
|
||||
listen, fun validate_cfg/1) of
|
||||
undefined ->
|
||||
[];
|
||||
@ -436,7 +438,8 @@ delete_listener(PortIP, Module, Opts) ->
|
||||
Ls
|
||||
end,
|
||||
Ports1 = lists:keydelete(PortIP1, 1, Ports),
|
||||
ejabberd_config:add_local_option(listen, Ports1),
|
||||
Ports2 = lists:map(fun transform_option/1, Ports1),
|
||||
ejabberd_config:add_option(listen, Ports2),
|
||||
stop_listener(PortIP1, Module).
|
||||
|
||||
|
||||
@ -541,6 +544,55 @@ format_error(Reason) ->
|
||||
-define(IS_PORT(P), (is_integer(P) and (P > 0) and (P =< 65535))).
|
||||
-define(IS_TRANSPORT(T), ((T == tcp) or (T == udp))).
|
||||
|
||||
transform_option({{Port, IP, Transport}, Mod, Opts}) ->
|
||||
IPStr = if is_tuple(IP) ->
|
||||
list_to_binary(inet_parse:ntoa(IP));
|
||||
true ->
|
||||
IP
|
||||
end,
|
||||
Opts1 = lists:map(
|
||||
fun({ip, IPT}) when is_tuple(IPT) ->
|
||||
{ip, list_to_binary(inet_parse:ntoa(IP))};
|
||||
(tls) -> {tls, true};
|
||||
(ssl) -> {tls, true};
|
||||
(zlib) -> {zlib, true};
|
||||
(starttls) -> {starttls, true};
|
||||
(starttls_required) -> {starttls_required, true};
|
||||
(Opt) -> Opt
|
||||
end, Opts),
|
||||
Opts2 = lists:foldl(
|
||||
fun(Opt, Acc) ->
|
||||
try
|
||||
Mod:transform_listen_option(Opt, Acc)
|
||||
catch error:undef ->
|
||||
Acc
|
||||
end
|
||||
end, [], Opts1),
|
||||
TransportOpt = if Transport == tcp -> [];
|
||||
true -> [{transport, Transport}]
|
||||
end,
|
||||
IPOpt = if IPStr == <<"0.0.0.0">> -> [];
|
||||
true -> [{ip, IPStr}]
|
||||
end,
|
||||
IPOpt ++ TransportOpt ++ [{port, Port}, {module, Mod} | Opts2];
|
||||
transform_option({{Port, Transport}, Mod, Opts})
|
||||
when ?IS_TRANSPORT(Transport) ->
|
||||
transform_option({{Port, {0,0,0,0}, Transport}, Mod, Opts});
|
||||
transform_option({{Port, IP}, Mod, Opts}) ->
|
||||
transform_option({{Port, IP, tcp}, Mod, Opts});
|
||||
transform_option({Port, Mod, Opts}) ->
|
||||
transform_option({{Port, {0,0,0,0}, tcp}, Mod, Opts});
|
||||
transform_option(Opt) ->
|
||||
Opt.
|
||||
|
||||
transform_options(Opts) ->
|
||||
lists:foldl(fun transform_options/2, [], Opts).
|
||||
|
||||
transform_options({listen, LOpts}, Opts) ->
|
||||
[{listen, lists:map(fun transform_option/1, LOpts)} | Opts];
|
||||
transform_options(Opt, Opts) ->
|
||||
[Opt|Opts].
|
||||
|
||||
-type transport() :: udp | tcp.
|
||||
-type port_ip_transport() :: inet:port_number() |
|
||||
{inet:port_number(), transport()} |
|
||||
@ -551,18 +603,21 @@ format_error(Reason) ->
|
||||
|
||||
validate_cfg(L) ->
|
||||
lists:map(
|
||||
fun({PortIPTransport, Mod1, Opts}) when is_atom(Mod1), is_list(Opts) ->
|
||||
Mod = prepare_mod(Mod1),
|
||||
case PortIPTransport of
|
||||
Port when ?IS_PORT(Port) ->
|
||||
{Port, Mod, Opts};
|
||||
{Port, Trans} when ?IS_PORT(Port) and ?IS_TRANSPORT(Trans) ->
|
||||
{{Port, Trans}, Mod, Opts};
|
||||
{Port, IP} when ?IS_PORT(Port) ->
|
||||
{{Port, prepare_ip(IP)}, Mod, Opts};
|
||||
{Port, IP, Trans} when ?IS_PORT(Port) and ?IS_TRANSPORT(Trans) ->
|
||||
{{Port, prepare_ip(IP), Trans}, Mod, Opts}
|
||||
end
|
||||
fun(LOpts) ->
|
||||
lists:foldl(
|
||||
fun({port, Port}, {{_, IP, T}, Mod, Opts}) ->
|
||||
true = ?IS_PORT(Port),
|
||||
{{Port, IP, T}, Mod, Opts};
|
||||
({ip, IP}, {{Port, _, T}, Mod, Opts}) ->
|
||||
{{Port, prepare_ip(IP), T}, Mod, Opts};
|
||||
({transport, T}, {{Port, IP, _}, Mod, Opts}) ->
|
||||
true = ?IS_TRANSPORT(T),
|
||||
{{Port, IP, T}, Mod, Opts};
|
||||
({module, Mod}, {Port, _, Opts}) ->
|
||||
{Port, prepare_mod(Mod), Opts};
|
||||
(Opt, {Port, Mod, Opts}) ->
|
||||
{Port, Mod, [Opt|Opts]}
|
||||
end, {{5222, {0,0,0,0}, tcp}, ejabberd_c2s, []}, LOpts)
|
||||
end, L).
|
||||
|
||||
prepare_ip({A, B, C, D} = IP)
|
||||
@ -583,5 +638,5 @@ prepare_mod(ejabberd_stun) ->
|
||||
prepare_mod(stun) ->
|
||||
ejabberd:start_app(p1_stun),
|
||||
stun;
|
||||
prepare_mod(Mod) ->
|
||||
prepare_mod(Mod) when is_atom(Mod) ->
|
||||
Mod.
|
||||
|
@ -84,7 +84,12 @@ get_closest_node(Name) ->
|
||||
%%--------------------------------------------------------------------
|
||||
init([]) ->
|
||||
{FE, BE} =
|
||||
case ejabberd_config:get_local_option(node_type, fun(N) -> N end) of
|
||||
case ejabberd_config:get_option(
|
||||
node_type,
|
||||
fun(frontend) -> frontend;
|
||||
(backend) -> backend;
|
||||
(generic) -> generic
|
||||
end, generic) of
|
||||
frontend ->
|
||||
{true, false};
|
||||
backend ->
|
||||
|
@ -71,12 +71,12 @@
|
||||
|
||||
-define(TOP_LEVEL_TXN, 0).
|
||||
|
||||
-define(MAX_TRANSACTION_RESTARTS, 10).
|
||||
|
||||
-define(PGSQL_PORT, 5432).
|
||||
|
||||
-define(MYSQL_PORT, 3306).
|
||||
|
||||
-define(MAX_TRANSACTION_RESTARTS, 10).
|
||||
|
||||
-define(TRANSACTION_TIMEOUT, 60000).
|
||||
|
||||
-define(KEEPALIVE_TIMEOUT, 60000).
|
||||
@ -201,8 +201,8 @@ decode_term(Bin) ->
|
||||
%%% Callback functions from gen_fsm
|
||||
%%%----------------------------------------------------------------------
|
||||
init([Host, StartInterval]) ->
|
||||
case ejabberd_config:get_local_option(
|
||||
{odbc_keepalive_interval, Host},
|
||||
case ejabberd_config:get_option(
|
||||
{keepalive_interval, Host},
|
||||
fun(I) when is_integer(I), I>0 -> I end) of
|
||||
undefined ->
|
||||
ok;
|
||||
@ -573,39 +573,39 @@ log(Level, Format, Args) ->
|
||||
end.
|
||||
|
||||
db_opts(Host) ->
|
||||
case ejabberd_config:get_local_option(
|
||||
{odbc_server, Host},
|
||||
fun({Type, Server, DB, User, Pass}) ->
|
||||
{Type,
|
||||
iolist_to_binary(Server),
|
||||
case Type of
|
||||
mysql -> ?MYSQL_PORT;
|
||||
pgsql -> ?PGSQL_PORT
|
||||
end,
|
||||
iolist_to_binary(DB),
|
||||
iolist_to_binary(User),
|
||||
iolist_to_binary(Pass)};
|
||||
({Type, Server, Port, DB, User, Pass})
|
||||
when ((Type == mysql) or (Type == pgsql))
|
||||
and (is_integer(Port) and ((Port > 0)
|
||||
and (Port < 65536))) ->
|
||||
{Type,
|
||||
iolist_to_binary(Server),
|
||||
Port,
|
||||
iolist_to_binary(DB),
|
||||
iolist_to_binary(User),
|
||||
iolist_to_binary(Pass)};
|
||||
(S) ->
|
||||
iolist_to_binary(S)
|
||||
end, <<"localhost">>) of
|
||||
{Type, Server, Port, DB, User, Pass} ->
|
||||
[Type, Server, Port, DB, User, Pass];
|
||||
SQLServer ->
|
||||
[odbc, SQLServer]
|
||||
Type = ejabberd_config:get_option({odbc_type, Host},
|
||||
fun(mysql) -> mysql;
|
||||
(pgsql) -> pgsql;
|
||||
(odbc) -> odbc
|
||||
end, odbc),
|
||||
Server = ejabberd_config:get_option({odbc_server, Host},
|
||||
fun iolist_to_binary/1,
|
||||
<<"localhost">>),
|
||||
case Type of
|
||||
odbc ->
|
||||
[odbc, Server];
|
||||
_ ->
|
||||
Port = ejabberd_config:get_option(
|
||||
{port, Host},
|
||||
fun(P) when is_integer(P), P > 0, P < 65536 -> P end,
|
||||
case Type of
|
||||
mysql -> ?MYSQL_PORT;
|
||||
pgsql -> ?PGSQL_PORT
|
||||
end),
|
||||
DB = ejabberd_config:get_option({odbc_database, Host},
|
||||
fun iolist_to_binary/1,
|
||||
<<"ejabberd">>),
|
||||
User = ejabberd_config:get_option({odbc_username, Host},
|
||||
fun iolist_to_binary/1,
|
||||
<<"ejabberd">>),
|
||||
Pass = ejabberd_config:get_option({odbc_password, Host},
|
||||
fun iolist_to_binary/1,
|
||||
<<"">>),
|
||||
[Type, Server, Port, DB, User, Pass]
|
||||
end.
|
||||
|
||||
max_fsm_queue() ->
|
||||
ejabberd_config:get_local_option(
|
||||
ejabberd_config:get_option(
|
||||
max_fsm_queue,
|
||||
fun(N) when is_integer(N), N > 0 -> N end).
|
||||
|
||||
|
@ -30,11 +30,15 @@
|
||||
|
||||
%% API
|
||||
-export([start_link/1, init/1, add_pid/2, remove_pid/2,
|
||||
get_pids/1, get_random_pid/1]).
|
||||
get_pids/1, get_random_pid/1, transform_options/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-define(PGSQL_PORT, 5432).
|
||||
|
||||
-define(MYSQL_PORT, 3306).
|
||||
|
||||
-define(DEFAULT_POOL_SIZE, 10).
|
||||
|
||||
-define(DEFAULT_ODBC_START_INTERVAL, 30).
|
||||
@ -56,11 +60,11 @@ start_link(Host) ->
|
||||
?MODULE, [Host]).
|
||||
|
||||
init([Host]) ->
|
||||
PoolSize = ejabberd_config:get_local_option(
|
||||
PoolSize = ejabberd_config:get_option(
|
||||
{odbc_pool_size, Host},
|
||||
fun(I) when is_integer(I), I>0 -> I end,
|
||||
?DEFAULT_POOL_SIZE),
|
||||
StartInterval = ejabberd_config:get_local_option(
|
||||
StartInterval = ejabberd_config:get_option(
|
||||
{odbc_start_interval, Host},
|
||||
fun(I) when is_integer(I), I>0 -> I end,
|
||||
?DEFAULT_ODBC_START_INTERVAL),
|
||||
@ -93,3 +97,20 @@ remove_pid(Host, Pid) ->
|
||||
mnesia:delete_object(#sql_pool{host = Host, pid = Pid})
|
||||
end,
|
||||
mnesia:ets(F).
|
||||
|
||||
transform_options(Opts) ->
|
||||
lists:foldl(fun transform_options/2, [], Opts).
|
||||
|
||||
transform_options({odbc_server, {Type, Server, Port, DB, User, Pass}}, Opts) ->
|
||||
[{odbc_type, Type},
|
||||
{odbc_server, Server},
|
||||
{odbc_port, Port},
|
||||
{odbc_database, DB},
|
||||
{odbc_username, User},
|
||||
{odbc_password, Pass}|Opts];
|
||||
transform_options({odbc_server, {mysql, Server, DB, User, Pass}}, Opts) ->
|
||||
transform_options({odbc_server, {mysql, Server, ?MYSQL_PORT, DB, User, Pass}}, Opts);
|
||||
transform_options({odbc_server, {pgsql, Server, DB, User, Pass}}, Opts) ->
|
||||
transform_options({odbc_server, {pgsql, Server, ?PGSQL_PORT, DB, User, Pass}}, Opts);
|
||||
transform_options(Opt, Opts) ->
|
||||
[Opt|Opts].
|
||||
|
@ -69,18 +69,16 @@ start_odbc(Host, App) ->
|
||||
start_odbc(Host, App)
|
||||
end.
|
||||
|
||||
%% Returns {true, App} if we have configured odbc_server for the given host
|
||||
%% Returns {true, App} if we have configured odbc for the given host
|
||||
needs_odbc(Host) ->
|
||||
LHost = jlib:nameprep(Host),
|
||||
case ejabberd_config:get_local_option(
|
||||
{odbc_server, LHost}, fun(Res) -> Res end) of
|
||||
{mysql, _, _, _, _} -> {true, p1_mysql};
|
||||
{pgsql, _, _, _, _} -> {true, p1_pgsql};
|
||||
{mysql, _, _, _, _, _} -> {true, p1_mysql};
|
||||
{pgsql, _, _, _, _, _} -> {true, p1_pgsql};
|
||||
S ->
|
||||
case catch iolist_to_binary(S) of
|
||||
{'EXIT', _} -> false;
|
||||
_ -> true
|
||||
end
|
||||
case ejabberd_config:get_option({odbc_type, LHost},
|
||||
fun(mysql) -> mysql;
|
||||
(pgsql) -> pgsql;
|
||||
(odbc) -> odbc
|
||||
end, undefined) of
|
||||
mysql -> {true, p1_mysql};
|
||||
pgsql -> {true, p1_pgsql};
|
||||
odbc -> {true, odbc};
|
||||
undefined -> false
|
||||
end.
|
||||
|
@ -387,14 +387,10 @@ do_route(OrigFrom, OrigTo, OrigPacket) ->
|
||||
end.
|
||||
|
||||
get_component_number(LDomain) ->
|
||||
case
|
||||
ejabberd_config:get_local_option({domain_balancing_component_number,
|
||||
LDomain}, fun(D) -> D end)
|
||||
of
|
||||
N when is_integer(N), N > 1 -> N;
|
||||
_ -> undefined
|
||||
end.
|
||||
|
||||
ejabberd_config:get_option(
|
||||
{domain_balancing_component_number, LDomain},
|
||||
fun(N) when is_integer(N), N > 1 -> N end,
|
||||
undefined).
|
||||
|
||||
update_tables() ->
|
||||
case catch mnesia:table_info(route, attributes) of
|
||||
|
@ -45,7 +45,7 @@
|
||||
handle_info/2, terminate/2, code_change/3]).
|
||||
|
||||
%% ejabberd API
|
||||
-export([get_info_s2s_connections/1]).
|
||||
-export([get_info_s2s_connections/1, transform_options/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
@ -461,12 +461,12 @@ needed_connections_number(Ls, MaxS2SConnectionsNumber,
|
||||
%% --------------------------------------------------------------------
|
||||
is_service(From, To) ->
|
||||
LFromDomain = From#jid.lserver,
|
||||
case ejabberd_config:get_local_option(
|
||||
case ejabberd_config:get_option(
|
||||
{route_subdomains, LFromDomain},
|
||||
fun(s2s) -> s2s end) of
|
||||
fun(s2s) -> s2s; (local) -> local end, local) of
|
||||
s2s -> % bypass RFC 3920 10.3
|
||||
false;
|
||||
undefined ->
|
||||
local ->
|
||||
Hosts = (?MYHOSTS),
|
||||
P = fun (ParentDomain) ->
|
||||
lists:member(ParentDomain, Hosts)
|
||||
@ -548,34 +548,50 @@ allow_host2(MyServer, S2SHost) ->
|
||||
end.
|
||||
|
||||
allow_host1(MyHost, S2SHost) ->
|
||||
case ejabberd_config:get_local_option(
|
||||
{{s2s_host, S2SHost}, MyHost},
|
||||
fun(deny) -> deny; (allow) -> allow end)
|
||||
of
|
||||
deny -> false;
|
||||
allow -> true;
|
||||
undefined ->
|
||||
case ejabberd_config:get_local_option(
|
||||
{s2s_default_policy, MyHost},
|
||||
fun(deny) -> deny; (allow) -> allow end)
|
||||
of
|
||||
deny -> false;
|
||||
_ ->
|
||||
case ejabberd_hooks:run_fold(s2s_allow_host, MyHost,
|
||||
allow, [MyHost, S2SHost])
|
||||
of
|
||||
deny -> false;
|
||||
allow -> true;
|
||||
_ -> true
|
||||
end
|
||||
end
|
||||
Rule = ejabberd_config:get_option(
|
||||
s2s_access,
|
||||
fun(A) when is_atom(A) -> A end,
|
||||
all),
|
||||
JID = jlib:make_jid(<<"">>, S2SHost, <<"">>),
|
||||
case acl:match_rule(MyHost, Rule, JID) of
|
||||
deny -> false;
|
||||
allow ->
|
||||
case ejabberd_hooks:run_fold(s2s_allow_host, MyHost,
|
||||
allow, [MyHost, S2SHost]) of
|
||||
deny -> false;
|
||||
allow -> true;
|
||||
_ -> true
|
||||
end
|
||||
end.
|
||||
|
||||
transform_options(Opts) ->
|
||||
lists:foldl(fun transform_options/2, [], Opts).
|
||||
|
||||
transform_options({{s2s_host, Host}, Action}, Opts) ->
|
||||
?WARNING_MSG("Option 's2s_host' is deprecated. "
|
||||
"The option is still supported but it is better to "
|
||||
"fix your config: use access rules instead.", []),
|
||||
ACLName = jlib:binary_to_atom(
|
||||
iolist_to_binary(["s2s_access_", Host])),
|
||||
[{acl, ACLName, {server, Host}},
|
||||
{access, s2s, [{Action, ACLName}]},
|
||||
{s2s_access, s2s} |
|
||||
Opts];
|
||||
transform_options({s2s_default_policy, Action}, Opts) ->
|
||||
?WARNING_MSG("Option 's2s_default_policy' is deprecated. "
|
||||
"The option is still supported but it is better to "
|
||||
"fix your config: "
|
||||
"use 's2s_access' with an access rule.", []),
|
||||
[{access, s2s, [{Action, all}]},
|
||||
{s2s_access, s2s} |
|
||||
Opts];
|
||||
transform_options(Opt, Opts) ->
|
||||
[Opt|Opts].
|
||||
|
||||
%% Get information about S2S connections of the specified type.
|
||||
%% @spec (Type) -> [Info]
|
||||
%% where Type = in | out
|
||||
%% Info = [{InfoName::atom(), InfoValue::any()}]
|
||||
|
||||
get_info_s2s_connections(Type) ->
|
||||
ChildType = case Type of
|
||||
in -> ejabberd_s2s_in_sup;
|
||||
|
@ -149,7 +149,7 @@ init([{SockMod, Socket}, Opts]) ->
|
||||
_ -> none
|
||||
end,
|
||||
{StartTLS, TLSRequired, TLSCertverify} =
|
||||
case ejabberd_config:get_local_option(
|
||||
case ejabberd_config:get_option(
|
||||
s2s_use_starttls,
|
||||
fun(false) -> false;
|
||||
(true) -> true;
|
||||
@ -171,7 +171,7 @@ init([{SockMod, Socket}, Opts]) ->
|
||||
required_trusted ->
|
||||
{true, true, true}
|
||||
end,
|
||||
TLSOpts1 = case ejabberd_config:get_local_option(
|
||||
TLSOpts1 = case ejabberd_config:get_option(
|
||||
s2s_certfile,
|
||||
fun iolist_to_binary/1) of
|
||||
undefined -> [];
|
||||
@ -324,7 +324,7 @@ wait_for_feature_request({xmlstreamelement, El},
|
||||
?DEBUG("starttls", []),
|
||||
Socket = StateData#state.socket,
|
||||
TLSOpts1 = case
|
||||
ejabberd_config:get_local_option(
|
||||
ejabberd_config:get_option(
|
||||
{domain_certfile, StateData#state.server},
|
||||
fun iolist_to_binary/1) of
|
||||
undefined -> StateData#state.tls_options;
|
||||
@ -332,7 +332,7 @@ wait_for_feature_request({xmlstreamelement, El},
|
||||
[{certfile, CertFile} | lists:keydelete(certfile, 1,
|
||||
StateData#state.tls_options)]
|
||||
end,
|
||||
TLSOpts = case ejabberd_config:get_local_option(
|
||||
TLSOpts = case ejabberd_config:get_option(
|
||||
{s2s_tls_compression, StateData#state.server},
|
||||
fun(true) -> true;
|
||||
(false) -> false
|
||||
@ -843,7 +843,7 @@ fsm_limit_opts(Opts) ->
|
||||
case lists:keysearch(max_fsm_queue, 1, Opts) of
|
||||
{value, {_, N}} when is_integer(N) -> [{max_queue, N}];
|
||||
_ ->
|
||||
case ejabberd_config:get_local_option(
|
||||
case ejabberd_config:get_option(
|
||||
max_fsm_queue,
|
||||
fun(I) when is_integer(I), I > 0 -> I end) of
|
||||
undefined -> [];
|
||||
|
@ -35,7 +35,8 @@
|
||||
start_link/3,
|
||||
start_connection/1,
|
||||
terminate_if_waiting_delay/2,
|
||||
stop_connection/1]).
|
||||
stop_connection/1,
|
||||
transform_options/1]).
|
||||
|
||||
%% p1_fsm callbacks (same as gen_fsm)
|
||||
-export([init/1,
|
||||
@ -161,7 +162,7 @@ init([From, Server, Type]) ->
|
||||
process_flag(trap_exit, true),
|
||||
?DEBUG("started: ~p", [{From, Server, Type}]),
|
||||
{TLS, TLSRequired} = case
|
||||
ejabberd_config:get_local_option(
|
||||
ejabberd_config:get_option(
|
||||
s2s_use_starttls,
|
||||
fun(true) -> true;
|
||||
(false) -> false;
|
||||
@ -184,13 +185,13 @@ init([From, Server, Type]) ->
|
||||
end,
|
||||
UseV10 = TLS,
|
||||
TLSOpts1 = case
|
||||
ejabberd_config:get_local_option(
|
||||
ejabberd_config:get_option(
|
||||
s2s_certfile, fun iolist_to_binary/1)
|
||||
of
|
||||
undefined -> [connect];
|
||||
CertFile -> [{certfile, CertFile}, connect]
|
||||
end,
|
||||
TLSOpts = case ejabberd_config:get_local_option(
|
||||
TLSOpts = case ejabberd_config:get_option(
|
||||
{s2s_tls_compression, From},
|
||||
fun(true) -> true;
|
||||
(false) -> false
|
||||
@ -702,7 +703,7 @@ wait_for_starttls_proceed({xmlstreamelement, El},
|
||||
[{StateData#state.myname, StateData#state.server}]),
|
||||
Socket = StateData#state.socket,
|
||||
TLSOpts = case
|
||||
ejabberd_config:get_local_option(
|
||||
ejabberd_config:get_option(
|
||||
{domain_certfile, StateData#state.myname},
|
||||
fun iolist_to_binary/1)
|
||||
of
|
||||
@ -1142,16 +1143,15 @@ get_addr_port(Server) ->
|
||||
end.
|
||||
|
||||
srv_lookup(Server) ->
|
||||
Options = case
|
||||
ejabberd_config:get_local_option(
|
||||
s2s_dns_options, fun(L) when is_list(L) -> L end)
|
||||
of
|
||||
undefined -> [];
|
||||
L -> L
|
||||
end,
|
||||
TimeoutMs = timer:seconds(proplists:get_value(timeout,
|
||||
Options, 10)),
|
||||
Retries = proplists:get_value(retries, Options, 2),
|
||||
TimeoutMs = timer:seconds(
|
||||
ejabberd_config:get_option(
|
||||
s2s_dns_timeout,
|
||||
fun(I) when is_integer(I), I>=0 -> I end,
|
||||
10)),
|
||||
Retries = ejabberd_config:get_option(
|
||||
s2s_dns_retries,
|
||||
fun(I) when is_integer(I), I>=0 -> I end,
|
||||
2),
|
||||
srv_lookup(binary_to_list(Server), TimeoutMs, Retries).
|
||||
|
||||
%% XXX - this behaviour is suboptimal in the case that the domain
|
||||
@ -1211,15 +1211,15 @@ get_addrs(Host, Family) ->
|
||||
end.
|
||||
|
||||
outgoing_s2s_port() ->
|
||||
ejabberd_config:get_local_option(
|
||||
ejabberd_config:get_option(
|
||||
outgoing_s2s_port,
|
||||
fun(I) when is_integer(I), I > 0, I =< 65536 -> I end,
|
||||
5269).
|
||||
|
||||
outgoing_s2s_families() ->
|
||||
ejabberd_config:get_local_option(
|
||||
outgoing_s2s_options,
|
||||
fun({Families, _}) ->
|
||||
ejabberd_config:get_option(
|
||||
outgoing_s2s_families,
|
||||
fun(Families) ->
|
||||
true = lists:all(
|
||||
fun(ipv4) -> true;
|
||||
(ipv6) -> true
|
||||
@ -1228,14 +1228,43 @@ outgoing_s2s_families() ->
|
||||
end, [ipv4, ipv6]).
|
||||
|
||||
outgoing_s2s_timeout() ->
|
||||
ejabberd_config:get_local_option(
|
||||
outgoing_s2s_options,
|
||||
fun({_, TimeOut}) when is_integer(TimeOut), TimeOut > 0 ->
|
||||
ejabberd_config:get_option(
|
||||
outgoing_s2s_timeout,
|
||||
fun(TimeOut) when is_integer(TimeOut), TimeOut > 0 ->
|
||||
TimeOut;
|
||||
({_, infinity}) ->
|
||||
(infinity) ->
|
||||
infinity
|
||||
end, 10000).
|
||||
|
||||
transform_options(Opts) ->
|
||||
lists:foldl(fun transform_options/2, [], Opts).
|
||||
|
||||
transform_options({outgoing_s2s_options, Families, Timeout}, Opts) ->
|
||||
?WARNING_MSG("Option 'outgoing_s2s_options' is deprecated. "
|
||||
"The option is still supported "
|
||||
"but it is better to fix your config: "
|
||||
"use 'outgoing_s2s_timeout' and "
|
||||
"'outgoing_s2s_families' instead.", []),
|
||||
[{outgoing_s2s_families, Families},
|
||||
{outgoing_s2s_timeout, Timeout}
|
||||
| Opts];
|
||||
transform_options({s2s_dns_options, S2SDNSOpts}, AllOpts) ->
|
||||
?WARNING_MSG("Option 's2s_dns_options' is deprecated. "
|
||||
"The option is still supported "
|
||||
"but it is better to fix your config: "
|
||||
"use 's2s_dns_timeout' and "
|
||||
"'s2s_dns_retries' instead", []),
|
||||
lists:foldr(
|
||||
fun({timeout, T}, AccOpts) ->
|
||||
[{s2s_dns_timeout, T}|AccOpts];
|
||||
({retries, R}, AccOpts) ->
|
||||
[{s2s_dns_retries, R}|AccOpts];
|
||||
(_, AccOpts) ->
|
||||
AccOpts
|
||||
end, AllOpts, S2SDNSOpts);
|
||||
transform_options(Opt, Opts) ->
|
||||
[Opt|Opts].
|
||||
|
||||
%% Human readable S2S logging: Log only new outgoing connections as INFO
|
||||
%% Do not log dialback
|
||||
log_s2s_out(false, _, _, _) -> ok;
|
||||
@ -1278,7 +1307,7 @@ wait_before_reconnect(StateData) ->
|
||||
queue = queue:new()}}.
|
||||
|
||||
get_max_retry_delay() ->
|
||||
case ejabberd_config:get_local_option(
|
||||
case ejabberd_config:get_option(
|
||||
s2s_max_retry_delay,
|
||||
fun(I) when is_integer(I), I > 0 -> I end) of
|
||||
undefined -> ?MAX_RETRY_DELAY;
|
||||
@ -1295,7 +1324,7 @@ terminate_if_waiting_delay(From, To) ->
|
||||
Pids).
|
||||
|
||||
fsm_limit_opts() ->
|
||||
case ejabberd_config:get_local_option(
|
||||
case ejabberd_config:get_option(
|
||||
max_fsm_queue,
|
||||
fun(I) when is_integer(I), I > 0 -> I end) of
|
||||
undefined -> [];
|
||||
|
@ -34,7 +34,7 @@
|
||||
|
||||
%% External exports
|
||||
-export([start/2, start_link/2, send_text/2,
|
||||
send_element/2, socket_type/0]).
|
||||
send_element/2, socket_type/0, transform_listen_option/2]).
|
||||
|
||||
%% gen_fsm callbacks
|
||||
-export([init/1, wait_for_stream/2,
|
||||
@ -124,29 +124,18 @@ init([{SockMod, Socket}, Opts]) ->
|
||||
{value, {_, A}} -> A;
|
||||
_ -> all
|
||||
end,
|
||||
{Hosts, Password} = case lists:keysearch(hosts, 1, Opts)
|
||||
of
|
||||
{value, {_, Hs, HOpts}} ->
|
||||
case lists:keysearch(password, 1, HOpts) of
|
||||
{value, {_, P}} -> {Hs, P};
|
||||
_ ->
|
||||
% TODO: generate error
|
||||
false
|
||||
end;
|
||||
_ ->
|
||||
case lists:keysearch(host, 1, Opts) of
|
||||
{value, {_, H, HOpts}} ->
|
||||
case lists:keysearch(password, 1, HOpts) of
|
||||
{value, {_, P}} -> {[H], P};
|
||||
_ ->
|
||||
% TODO: generate error
|
||||
false
|
||||
end;
|
||||
_ ->
|
||||
% TODO: generate error
|
||||
false
|
||||
end
|
||||
end,
|
||||
%% This should be improved probably
|
||||
{Hosts, HostOpts} = case lists:keyfind(hosts, 1, Opts) of
|
||||
{_, HOpts} ->
|
||||
{[H || {H, _} <- HOpts],
|
||||
lists:flatten(
|
||||
[O || {_, O} <- HOpts])};
|
||||
_ ->
|
||||
{[], []}
|
||||
end,
|
||||
Password = gen_mod:get_opt(password, HostOpts,
|
||||
fun iolist_to_binary/1,
|
||||
p1_sha:sha(crypto:rand_bytes(20))),
|
||||
Shaper = case lists:keysearch(shaper_rule, 1, Opts) of
|
||||
{value, {_, S}} -> S;
|
||||
_ -> none
|
||||
@ -384,12 +373,30 @@ send_element(StateData, El) ->
|
||||
|
||||
new_id() -> randoms:get_string().
|
||||
|
||||
transform_listen_option({hosts, Hosts, O}, Opts) ->
|
||||
case lists:keyfind(hosts, 1, Opts) of
|
||||
{_, PrevHostOpts} ->
|
||||
NewHostOpts =
|
||||
lists:foldl(
|
||||
fun(H, Acc) ->
|
||||
dict:append_list(H, O, Acc)
|
||||
end, dict:from_list(PrevHostOpts), Hosts),
|
||||
[{hosts, dict:to_list(NewHostOpts)}|
|
||||
lists:keydelete(hosts, 1, Opts)];
|
||||
_ ->
|
||||
[{hosts, [{H, O} || H <- Hosts]}|Opts]
|
||||
end;
|
||||
transform_listen_option({host, Host, Os}, Opts) ->
|
||||
transform_listen_option({hosts, [Host], Os}, Opts);
|
||||
transform_listen_option(Opt, Opts) ->
|
||||
[Opt|Opts].
|
||||
|
||||
fsm_limit_opts(Opts) ->
|
||||
case lists:keysearch(max_fsm_queue, 1, Opts) of
|
||||
{value, {_, N}} when is_integer(N) ->
|
||||
[{max_queue, N}];
|
||||
_ ->
|
||||
case ejabberd_config:get_local_option(
|
||||
case ejabberd_config:get_option(
|
||||
max_fsm_queue,
|
||||
fun(I) when is_integer(I), I > 0 -> I end) of
|
||||
undefined -> [];
|
||||
|
@ -53,7 +53,7 @@
|
||||
%% Description: Starts the server
|
||||
%%--------------------------------------------------------------------
|
||||
start_link() ->
|
||||
LH = ejabberd_config:get_local_option(
|
||||
LH = ejabberd_config:get_option(
|
||||
watchdog_large_heap,
|
||||
fun(I) when is_integer(I), I > 0 -> I end,
|
||||
1000000),
|
||||
@ -200,7 +200,7 @@ send_message(From, To, Body) ->
|
||||
[{xmlcdata, Body}]}]}).
|
||||
|
||||
get_admin_jids() ->
|
||||
ejabberd_config:get_local_option(
|
||||
ejabberd_config:get_option(
|
||||
watchdog_admins,
|
||||
fun(JIDs) ->
|
||||
[jlib:jid_tolower(
|
||||
|
@ -827,14 +827,14 @@ process_admin(Host,
|
||||
{value, {_, String}} ->
|
||||
case parse_access_rule(String) of
|
||||
{ok, Rs} ->
|
||||
ejabberd_config:add_global_option({access, Name, Host},
|
||||
ejabberd_config:add_option({access, Name, Host},
|
||||
Rs),
|
||||
ok;
|
||||
_ -> error
|
||||
end;
|
||||
_ -> nothing
|
||||
end,
|
||||
Rules = case ejabberd_config:get_global_option(
|
||||
Rules = case ejabberd_config:get_option(
|
||||
{access, Name, Host}, fun(V) -> V end)
|
||||
of
|
||||
undefined -> [];
|
||||
@ -1198,7 +1198,7 @@ access_parse_addnew(_AccessRules, Host, Query) ->
|
||||
case lists:keysearch(<<"namenew">>, 1, Query) of
|
||||
{value, {_, String}} when String /= <<"">> ->
|
||||
Name = jlib:binary_to_atom(String),
|
||||
ejabberd_config:add_global_option({access, Name, Host},
|
||||
ejabberd_config:add_option({access, Name, Host},
|
||||
[]),
|
||||
ok
|
||||
end.
|
||||
|
@ -182,7 +182,7 @@ get_opt({Key, Host}, Opts, F) ->
|
||||
get_opt({Key, Host}, Opts, F, Default) ->
|
||||
case gen_mod:get_opt(Key, Opts, F, undefined) of
|
||||
undefined ->
|
||||
ejabberd_config:get_local_option(
|
||||
ejabberd_config:get_option(
|
||||
{Key, Host}, F, Default);
|
||||
Val ->
|
||||
Val
|
||||
|
@ -106,7 +106,7 @@ random_instance(MaxNum) ->
|
||||
random:uniform(MaxNum) - 1.
|
||||
|
||||
get_instances(Server) ->
|
||||
ejabberd_config:get_local_option(
|
||||
ejabberd_config:get_option(
|
||||
{extauth_instances, Server},
|
||||
fun(V) when is_integer(V), V > 0 ->
|
||||
V
|
||||
|
@ -33,7 +33,7 @@
|
||||
%% API
|
||||
-export([start_link/3, add_iq_handler/6,
|
||||
remove_iq_handler/3, stop_iq_handler/3, handle/7,
|
||||
process_iq/6, check_type/1]).
|
||||
process_iq/6, check_type/1, transform_module_options/1]).
|
||||
|
||||
%% gen_server callbacks
|
||||
-export([init/1, handle_call/3, handle_cast/2,
|
||||
@ -46,7 +46,7 @@
|
||||
-record(state, {host, module, function}).
|
||||
|
||||
-type component() :: ejabberd_sm | ejabberd_local.
|
||||
-type type() :: no_queue | one_queue | {queues, pos_integer()} | parallel.
|
||||
-type type() :: no_queue | one_queue | pos_integer() | parallel.
|
||||
-type opts() :: no_queue | {one_queue, pid()} | {queues, [pid()]} | parallel.
|
||||
|
||||
%%====================================================================
|
||||
@ -71,7 +71,7 @@ add_iq_handler(Component, Host, NS, Module, Function,
|
||||
[Host, Module, Function]),
|
||||
Component:register_iq_handler(Host, NS, Module,
|
||||
Function, {one_queue, Pid});
|
||||
{queues, N} ->
|
||||
N when is_integer(N) ->
|
||||
Pids = lists:map(fun (_) ->
|
||||
{ok, Pid} =
|
||||
supervisor:start_child(ejabberd_iq_sup,
|
||||
@ -130,9 +130,19 @@ process_iq(_Host, Module, Function, From, To, IQ) ->
|
||||
|
||||
check_type(no_queue) -> no_queue;
|
||||
check_type(one_queue) -> one_queue;
|
||||
check_type({queues, N}) when is_integer(N), N>0 -> {queues, N};
|
||||
check_type(N) when is_integer(N), N>0 -> N;
|
||||
check_type(parallel) -> parallel.
|
||||
|
||||
-spec transform_module_options([{atom(), any()}]) -> [{atom(), any()}].
|
||||
|
||||
transform_module_options(Opts) ->
|
||||
lists:map(
|
||||
fun({iqdisc, {queues, N}}) ->
|
||||
{iqdisc, N};
|
||||
(Opt) ->
|
||||
Opt
|
||||
end, Opts).
|
||||
|
||||
%%====================================================================
|
||||
%% gen_server callbacks
|
||||
%%====================================================================
|
||||
|
@ -64,13 +64,11 @@ start() ->
|
||||
-spec start_module(binary(), atom(), opts()) -> any().
|
||||
|
||||
start_module(Host, Module, Opts) ->
|
||||
set_module_opts_mnesia(Host, Module, Opts),
|
||||
ets:insert(ejabberd_modules,
|
||||
#ejabberd_module{module_host = {Module, Host},
|
||||
opts = Opts}),
|
||||
try Module:start(Host, Opts) catch
|
||||
Class:Reason ->
|
||||
del_module_mnesia(Host, Module),
|
||||
ets:delete(ejabberd_modules, {Module, Host}),
|
||||
ErrorText =
|
||||
io_lib:format("Problem starting the module ~p for host "
|
||||
@ -101,7 +99,7 @@ is_app_running(AppName) ->
|
||||
stop_module(Host, Module) ->
|
||||
case stop_module_keep_config(Host, Module) of
|
||||
error -> error;
|
||||
ok -> del_module_mnesia(Host, Module)
|
||||
ok -> ok
|
||||
end.
|
||||
|
||||
%% @doc Stop the module in a host, but keep its configuration.
|
||||
@ -232,25 +230,6 @@ loaded_modules_with_opts(Host) ->
|
||||
opts = '$2'},
|
||||
[], [{{'$1', '$2'}}]}]).
|
||||
|
||||
set_module_opts_mnesia(Host, Module, Opts) ->
|
||||
Modules = ejabberd_config:get_local_option(
|
||||
{modules, Host},
|
||||
fun(Ls) when is_list(Ls) -> Ls end,
|
||||
[]),
|
||||
Modules1 = lists:keydelete(Module, 1, Modules),
|
||||
Modules2 = [{Module, Opts} | Modules1],
|
||||
ejabberd_config:add_local_option({modules, Host},
|
||||
Modules2).
|
||||
|
||||
del_module_mnesia(Host, Module) ->
|
||||
Modules = ejabberd_config:get_local_option(
|
||||
{modules, Host},
|
||||
fun(Ls) when is_list(Ls) -> Ls end,
|
||||
[]),
|
||||
Modules1 = lists:keydelete(Module, 1, Modules),
|
||||
ejabberd_config:add_local_option({modules, Host},
|
||||
Modules1).
|
||||
|
||||
-spec get_hosts(opts(), binary()) -> [binary()].
|
||||
|
||||
get_hosts(Opts, Prefix) ->
|
||||
|
@ -3,7 +3,7 @@
|
||||
%%% Author : Eric Cestari <ecestari@process-one.net>
|
||||
%%% Purpose : Message Carbons XEP-0280 0.8
|
||||
%%% Created : 5 May 2008 by Mickael Remond <mremond@process-one.net>
|
||||
%%% Usage : Add the following line in modules section of ejabberd.cfg:
|
||||
%%% Usage : Add the following line in modules section of ejabberd.yml:
|
||||
%%% {mod_carboncopy, []}
|
||||
%%%
|
||||
%%%
|
||||
|
@ -129,7 +129,7 @@ process_get(#xmlel{name = <<"info">>}) ->
|
||||
children = []}};
|
||||
process_get(#xmlel{name = <<"welcome-message">>,
|
||||
attrs = Attrs}) ->
|
||||
{Subj, Body} = ejabberd_config:get_local_option(
|
||||
{Subj, Body} = ejabberd_config:get_option(
|
||||
welcome_message,
|
||||
fun({Subj, Body}) ->
|
||||
{iolist_to_binary(Subj),
|
||||
@ -145,7 +145,7 @@ process_get(#xmlel{name = <<"welcome-message">>,
|
||||
children = [{xmlcdata, Body}]}]}};
|
||||
process_get(#xmlel{name = <<"registration-watchers">>,
|
||||
attrs = Attrs}) ->
|
||||
SubEls = ejabberd_config:get_local_option(
|
||||
SubEls = ejabberd_config:get_option(
|
||||
registration_watchers,
|
||||
fun(JIDs) when is_list(JIDs) ->
|
||||
lists:map(
|
||||
|
@ -36,7 +36,8 @@
|
||||
process_sm_iq_items/3, process_sm_iq_info/3,
|
||||
get_sm_identity/5, get_sm_features/5, get_sm_items/5,
|
||||
get_info/5, register_feature/2, unregister_feature/2,
|
||||
register_extra_domain/2, unregister_extra_domain/2]).
|
||||
register_extra_domain/2, unregister_extra_domain/2,
|
||||
transform_module_options/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
@ -440,6 +441,22 @@ get_user_resources(User, Server) ->
|
||||
end,
|
||||
lists:sort(Rs)).
|
||||
|
||||
transform_module_options(Opts) ->
|
||||
lists:map(
|
||||
fun({server_info, Infos}) ->
|
||||
NewInfos = lists:map(
|
||||
fun({Modules, Name, URLs}) ->
|
||||
[[{modules, Modules},
|
||||
{name, Name},
|
||||
{urls, URLs}]];
|
||||
(Opt) ->
|
||||
Opt
|
||||
end, Infos),
|
||||
{server_info, NewInfos};
|
||||
(Opt) ->
|
||||
Opt
|
||||
end, Opts).
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
%%% Support for: XEP-0157 Contact Addresses for XMPP Services
|
||||
@ -465,9 +482,17 @@ get_info(_A, Host, Mod, Node, _Lang) when Node == <<>> ->
|
||||
get_info(Acc, _, _, _Node, _) -> Acc.
|
||||
|
||||
get_fields_xml(Host, Module) ->
|
||||
Fields = gen_mod:get_module_opt(Host, ?MODULE, server_info,
|
||||
fun(L) when is_list(L) -> L end,
|
||||
[]),
|
||||
Fields = gen_mod:get_module_opt(
|
||||
Host, ?MODULE, server_info,
|
||||
fun(L) ->
|
||||
lists:map(
|
||||
fun(Opts) ->
|
||||
Mods = proplists:get_value(modules, Opts, all),
|
||||
Name = proplists:get_value(names, Opts, <<>>),
|
||||
URLs = proplists:get_value(urls, Opts, []),
|
||||
{Mods, Name, URLs}
|
||||
end, lists:flatmap(L))
|
||||
end, []),
|
||||
Fields_good = lists:filter(fun ({Modules, _, _}) ->
|
||||
case Modules of
|
||||
all -> true;
|
||||
|
@ -32,7 +32,8 @@
|
||||
|
||||
-export([start/2, stop/1, process_local_iq/3, export/1,
|
||||
process_sm_iq/3, on_presence_update/4, import/1, import/3,
|
||||
store_last_info/4, get_last_info/2, remove_user/2]).
|
||||
store_last_info/4, get_last_info/2, remove_user/2,
|
||||
transform_options/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
@ -101,18 +102,13 @@ process_local_iq(_From, _To,
|
||||
%% @doc Get the uptime of the ejabberd node, expressed in seconds.
|
||||
%% When ejabberd is starting, ejabberd_config:start/0 stores the datetime.
|
||||
get_node_uptime() ->
|
||||
case ejabberd_config:get_local_option(
|
||||
case ejabberd_config:get_option(
|
||||
node_start,
|
||||
fun({MegaSecs, Secs, MicroSecs} = Now)
|
||||
when is_integer(MegaSecs), MegaSecs >= 0,
|
||||
is_integer(Secs), Secs >= 0,
|
||||
is_integer(MicroSecs), MicroSecs >= 0 ->
|
||||
Now
|
||||
end) of
|
||||
fun(S) when is_integer(S), S >= 0 -> S end) of
|
||||
undefined ->
|
||||
trunc(element(1, erlang:statistics(wall_clock)) / 1000);
|
||||
StartNow ->
|
||||
now_to_seconds(now()) - now_to_seconds(StartNow)
|
||||
Now ->
|
||||
now_to_seconds(now()) - Now
|
||||
end.
|
||||
|
||||
now_to_seconds({MegaSecs, Secs, _MicroSecs}) ->
|
||||
@ -319,3 +315,13 @@ import(_LServer, mnesia, #last_activity{} = LA) ->
|
||||
mnesia:dirty_write(LA);
|
||||
import(_, _, _) ->
|
||||
pass.
|
||||
|
||||
transform_options(Opts) ->
|
||||
lists:foldl(fun transform_options/2, [], Opts).
|
||||
|
||||
transform_options({node_start, {_, _, _} = Now}, Opts) ->
|
||||
?WARNING_MSG("Old 'node_start' format detected. This is still supported "
|
||||
"but it is better to fix your config.", []),
|
||||
[{node_start, now_to_seconds(Now)}|Opts];
|
||||
transform_options(Opt, Opts) ->
|
||||
[Opt|Opts].
|
||||
|
@ -33,7 +33,7 @@
|
||||
-behaviour(gen_mod).
|
||||
|
||||
%% API
|
||||
-export([start_link/2, start/2, stop/1,
|
||||
-export([start_link/2, start/2, stop/1, transform_module_options/1,
|
||||
check_access_log/2, add_to_log/5]).
|
||||
|
||||
%% gen_server callbacks
|
||||
@ -111,6 +111,14 @@ check_access_log(Host, From) ->
|
||||
Res -> Res
|
||||
end.
|
||||
|
||||
transform_module_options(Opts) ->
|
||||
lists:map(
|
||||
fun({top_link, {S1, S2}}) ->
|
||||
{top_link, [{S1, S2}]};
|
||||
(Opt) ->
|
||||
Opt
|
||||
end, Opts).
|
||||
|
||||
%%====================================================================
|
||||
%% gen_server callbacks
|
||||
%%====================================================================
|
||||
@ -152,14 +160,14 @@ init([Host, Opts]) ->
|
||||
(universal) -> universal
|
||||
end, local),
|
||||
Top_link = gen_mod:get_opt(top_link, Opts,
|
||||
fun({S1, S2}) ->
|
||||
fun([{S1, S2}]) ->
|
||||
{iolist_to_binary(S1),
|
||||
iolist_to_binary(S2)}
|
||||
end, {<<"/">>, <<"Home">>}),
|
||||
NoFollow = gen_mod:get_opt(spam_prevention, Opts,
|
||||
fun(B) when is_boolean(B) -> B end,
|
||||
true),
|
||||
Lang = ejabberd_config:get_local_option(
|
||||
Lang = ejabberd_config:get_option(
|
||||
{language, Host},
|
||||
fun iolist_to_binary/1,
|
||||
?MYLANG),
|
||||
|
@ -33,7 +33,7 @@
|
||||
-behaviour(supervisor).
|
||||
|
||||
%% gen_mod callbacks.
|
||||
-export([start/2, stop/1]).
|
||||
-export([start/2, stop/1, transform_module_options/1]).
|
||||
|
||||
%% supervisor callbacks.
|
||||
-export([init/1]).
|
||||
@ -64,6 +64,9 @@ start_link(Host, Opts) ->
|
||||
supervisor:start_link({local, Proc}, ?MODULE,
|
||||
[Host, Opts]).
|
||||
|
||||
transform_module_options(Opts) ->
|
||||
mod_proxy65_service:transform_module_options(Opts).
|
||||
|
||||
init([Host, Opts]) ->
|
||||
Service = {mod_proxy65_service,
|
||||
{mod_proxy65_service, start_link, [Host, Opts]},
|
||||
|
@ -35,7 +35,7 @@
|
||||
handle_cast/2, terminate/2, code_change/3]).
|
||||
|
||||
%% API.
|
||||
-export([start_link/2, add_listener/2,
|
||||
-export([start_link/2, add_listener/2, transform_module_options/1,
|
||||
delete_listener/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
@ -261,16 +261,15 @@ parse_options(ServerHost, Opts) ->
|
||||
Name = gen_mod:get_opt(name, Opts, fun iolist_to_binary/1,
|
||||
<<"SOCKS5 Bytestreams">>),
|
||||
IP = gen_mod:get_opt(ip, Opts,
|
||||
fun(Addr) ->
|
||||
jlib:ip_to_list(Addr),
|
||||
fun(S) ->
|
||||
{ok, Addr} = inet_parse:address(
|
||||
binary_to_list(
|
||||
iolist_to_binary(S))),
|
||||
Addr
|
||||
end, get_my_ip()),
|
||||
HostName = gen_mod:get_opt(hostname, Opts,
|
||||
fun(Addr) when is_tuple(Addr) ->
|
||||
jlib:ip_to_list(Addr);
|
||||
(S) ->
|
||||
iolist_to_binary(S)
|
||||
end, jlib:ip_to_list(IP)),
|
||||
fun iolist_to_binary/1,
|
||||
jlib:ip_to_list(IP)),
|
||||
StreamAddr = [{<<"jid">>, MyHost},
|
||||
{<<"host">>, HostName},
|
||||
{<<"port">>, jlib:integer_to_binary(Port)}],
|
||||
@ -278,6 +277,16 @@ parse_options(ServerHost, Opts) ->
|
||||
name = Name, port = Port, ip = IP,
|
||||
stream_addr = StreamAddr, acl = ACL}.
|
||||
|
||||
transform_module_options(Opts) ->
|
||||
lists:map(
|
||||
fun({ip, IP}) when is_tuple(IP) ->
|
||||
{ip, jlib:ip_to_list(IP)};
|
||||
({hostname, IP}) when is_tuple(IP) ->
|
||||
{hostname, jlib:ip_to_list(IP)};
|
||||
(Opt) ->
|
||||
Opt
|
||||
end, Opts).
|
||||
|
||||
get_my_ip() ->
|
||||
{ok, MyHostName} = inet:gethostname(),
|
||||
case inet:getaddr(MyHostName, inet) of
|
||||
|
@ -279,10 +279,14 @@ select_auth_method(anonymous, AuthMethods) ->
|
||||
|
||||
%% Obviously, we must use shaper with maximum rate.
|
||||
find_maxrate(Shaper, JID1, JID2, Host) ->
|
||||
MaxRate1 = shaper:new(acl:match_rule(Host, Shaper,
|
||||
JID1)),
|
||||
MaxRate2 = shaper:new(acl:match_rule(Host, Shaper,
|
||||
JID2)),
|
||||
MaxRate1 = case acl:match_rule(Host, Shaper, JID1) of
|
||||
deny -> none;
|
||||
R1 -> shaper:new(R1)
|
||||
end,
|
||||
MaxRate2 = case acl:match_rule(Host, Shaper, JID2) of
|
||||
deny -> none;
|
||||
R2 -> shaper:new(R2)
|
||||
end,
|
||||
if MaxRate1 == none; MaxRate2 == none -> none;
|
||||
true -> lists:max([MaxRate1, MaxRate2])
|
||||
end.
|
||||
|
@ -32,7 +32,8 @@
|
||||
|
||||
-export([start/2, stop/1, stream_feature_register/2,
|
||||
unauthenticated_iq_register/4, try_register/5,
|
||||
process_iq/3, send_registration_notifications/3]).
|
||||
process_iq/3, send_registration_notifications/3,
|
||||
transform_options/1, transform_module_options/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
@ -418,7 +419,11 @@ try_register(User, Server, Password, SourceRaw, Lang) ->
|
||||
send_welcome_message(JID) ->
|
||||
Host = JID#jid.lserver,
|
||||
case gen_mod:get_module_opt(Host, ?MODULE, welcome_message,
|
||||
fun({S, B}) ->
|
||||
fun(Opts) ->
|
||||
S = proplists:get_value(
|
||||
subject, Opts, <<>>),
|
||||
B = proplists:get_value(
|
||||
body, Opts, <<>>),
|
||||
{iolist_to_binary(S),
|
||||
iolist_to_binary(B)}
|
||||
end, {<<"">>, <<"">>})
|
||||
@ -483,7 +488,7 @@ check_from(JID, Server) ->
|
||||
|
||||
check_timeout(undefined) -> true;
|
||||
check_timeout(Source) ->
|
||||
Timeout = ejabberd_config:get_local_option(
|
||||
Timeout = ejabberd_config:get_option(
|
||||
registration_timeout,
|
||||
fun(TO) when is_integer(TO), TO > 0 ->
|
||||
TO;
|
||||
@ -537,7 +542,7 @@ clean_treap(Treap, CleanPriority) ->
|
||||
|
||||
remove_timeout(undefined) -> true;
|
||||
remove_timeout(Source) ->
|
||||
Timeout = ejabberd_config:get_local_option(
|
||||
Timeout = ejabberd_config:get_option(
|
||||
registration_timeout,
|
||||
fun(TO) when is_integer(TO), TO > 0 ->
|
||||
TO;
|
||||
@ -604,6 +609,54 @@ is_strong_password(Server, Password) ->
|
||||
ejabberd_auth:entropy(Password) >= Entropy
|
||||
end.
|
||||
|
||||
transform_options(Opts) ->
|
||||
Opts1 = transform_ip_access(Opts),
|
||||
transform_module_options(Opts1).
|
||||
|
||||
transform_ip_access(Opts) ->
|
||||
try
|
||||
{value, {modules, ModOpts}, Opts1} = lists:keytake(modules, 1, Opts),
|
||||
{value, {?MODULE, RegOpts}, ModOpts1} = lists:keytake(?MODULE, 1, ModOpts),
|
||||
{value, {ip_access, L}, RegOpts1} = lists:keytake(ip_access, 1, RegOpts),
|
||||
true = is_list(L),
|
||||
?WARNING_MSG("Old 'ip_access' format detected. "
|
||||
"The old format is still supported "
|
||||
"but it is better to fix your config: "
|
||||
"use access rules instead.", []),
|
||||
ACLs = lists:flatmap(
|
||||
fun({Action, S}) ->
|
||||
ACLName = jlib:binary_to_atom(
|
||||
iolist_to_binary(
|
||||
["ip_", S])),
|
||||
[{Action, ACLName},
|
||||
{acl, ACLName, {ip, S}}]
|
||||
end, L),
|
||||
Access = {access, mod_register_networks,
|
||||
[{Action, ACLName} || {Action, ACLName} <- ACLs]},
|
||||
[ACL || {acl, _, _} = ACL <- ACLs] ++
|
||||
[Access,
|
||||
{modules,
|
||||
[{mod_register,
|
||||
[{ip_access, mod_register_networks}|RegOpts1]}
|
||||
| ModOpts1]}|Opts1]
|
||||
catch error:{badmatch, false} ->
|
||||
Opts
|
||||
end.
|
||||
|
||||
transform_module_options(Opts) ->
|
||||
lists:flatmap(
|
||||
fun({welcome_message, {Subj, Body}}) ->
|
||||
?WARNING_MSG("Old 'welcome_message' format detected. "
|
||||
"The old format is still supported "
|
||||
"but it is better to fix your config: "
|
||||
"change it to {welcome_message, "
|
||||
"[{subject, Subject}, {body, Body}]}",
|
||||
[]),
|
||||
[{welcome_message, [{subject, Subj}, {body, Body}]}];
|
||||
(Opt) ->
|
||||
[Opt]
|
||||
end, Opts).
|
||||
|
||||
%%%
|
||||
%%% ip_access management
|
||||
%%%
|
||||
@ -614,75 +667,15 @@ may_remove_resource(From) -> From.
|
||||
|
||||
get_ip_access(Host) ->
|
||||
gen_mod:get_module_opt(Host, ?MODULE, ip_access,
|
||||
fun(IPAccess) ->
|
||||
lists:flatmap(
|
||||
fun({Access, S}) ->
|
||||
{ok, IP, Mask} =
|
||||
parse_ip_netmask(
|
||||
iolist_to_binary(S)),
|
||||
[{Access, IP, Mask}]
|
||||
end, IPAccess)
|
||||
end, []).
|
||||
fun(A) when is_atom(A) -> A end,
|
||||
all).
|
||||
|
||||
parse_ip_netmask(S) ->
|
||||
case str:tokens(S, <<"/">>) of
|
||||
[IPStr] ->
|
||||
case inet_parse:address(binary_to_list(IPStr)) of
|
||||
{ok, {_, _, _, _} = IP} -> {ok, IP, 32};
|
||||
{ok, {_, _, _, _, _, _, _, _} = IP} -> {ok, IP, 128};
|
||||
_ -> error
|
||||
end;
|
||||
[IPStr, MaskStr] ->
|
||||
case catch jlib:binary_to_integer(MaskStr) of
|
||||
Mask when is_integer(Mask), Mask >= 0 ->
|
||||
case inet_parse:address(binary_to_list(IPStr)) of
|
||||
{ok, {_, _, _, _} = IP} when Mask =< 32 ->
|
||||
{ok, IP, Mask};
|
||||
{ok, {_, _, _, _, _, _, _, _} = IP} when Mask =< 128 ->
|
||||
{ok, IP, Mask};
|
||||
_ -> error
|
||||
end;
|
||||
_ -> error
|
||||
end;
|
||||
_ -> error
|
||||
end.
|
||||
|
||||
check_ip_access(_Source, []) -> allow;
|
||||
check_ip_access({User, Server, Resource}, IPAccess) ->
|
||||
case ejabberd_sm:get_user_ip(User, Server, Resource) of
|
||||
{IPAddress, _PortNumber} ->
|
||||
check_ip_access(IPAddress, IPAccess);
|
||||
_ -> true
|
||||
{IPAddress, _PortNumber} ->
|
||||
check_ip_access(IPAddress, IPAccess);
|
||||
_ ->
|
||||
deny
|
||||
end;
|
||||
check_ip_access({_, _, _, _} = IP,
|
||||
[{Access, {_, _, _, _} = Net, Mask} | IPAccess]) ->
|
||||
IPInt = ip_to_integer(IP),
|
||||
NetInt = ip_to_integer(Net),
|
||||
M = bnot (1 bsl (32 - Mask) - 1),
|
||||
if IPInt band M =:= NetInt band M -> Access;
|
||||
true -> check_ip_access(IP, IPAccess)
|
||||
end;
|
||||
check_ip_access({_, _, _, _, _, _, _, _} = IP,
|
||||
[{Access, {_, _, _, _, _, _, _, _} = Net, Mask}
|
||||
| IPAccess]) ->
|
||||
IPInt = ip_to_integer(IP),
|
||||
NetInt = ip_to_integer(Net),
|
||||
M = bnot (1 bsl (128 - Mask) - 1),
|
||||
if IPInt band M =:= NetInt band M -> Access;
|
||||
true -> check_ip_access(IP, IPAccess)
|
||||
end;
|
||||
check_ip_access(IP, [_ | IPAccess]) ->
|
||||
check_ip_access(IP, IPAccess).
|
||||
|
||||
ip_to_integer({IP1, IP2, IP3, IP4}) ->
|
||||
IP1 bsl 8 bor IP2 bsl 8 bor IP3 bsl 8 bor IP4;
|
||||
ip_to_integer({IP1, IP2, IP3, IP4, IP5, IP6, IP7,
|
||||
IP8}) ->
|
||||
IP1 bsl 16 bor IP2 bsl 16 bor IP3 bsl 16 bor IP4 bsl 16
|
||||
bor IP5
|
||||
bsl 16
|
||||
bor IP6
|
||||
bsl 16
|
||||
bor IP7
|
||||
bsl 16
|
||||
bor IP8.
|
||||
check_ip_access(IPAddress, IPAccess) ->
|
||||
acl:match_rule(global, IPAccess, IPAddress).
|
||||
|
@ -38,7 +38,7 @@
|
||||
|
||||
-export([start/2, start_link/2, stop/1,
|
||||
get_sm_features/5, process_local_iq/3, process_sm_iq/3,
|
||||
remove_user/1, route/4]).
|
||||
remove_user/1, route/4, transform_module_options/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
@ -767,7 +767,7 @@ parse_options(Host, Opts) ->
|
||||
VCardMap = gen_mod:get_opt(ldap_vcard_map, Opts,
|
||||
fun(Ls) ->
|
||||
lists:map(
|
||||
fun({S, P, L}) ->
|
||||
fun({S, [{P, L}]}) ->
|
||||
{iolist_to_binary(S),
|
||||
iolist_to_binary(P),
|
||||
[iolist_to_binary(E)
|
||||
@ -823,6 +823,20 @@ parse_options(Host, Opts) ->
|
||||
search_reported_attrs = SearchReportedAttrs,
|
||||
matches = Matches}.
|
||||
|
||||
transform_module_options(Opts) ->
|
||||
lists:map(
|
||||
fun({ldap_vcard_map, Map}) ->
|
||||
NewMap = lists:map(
|
||||
fun({Field, Pattern, Attrs}) ->
|
||||
{Field, [{Pattern, Attrs}]};
|
||||
(Opt) ->
|
||||
Opt
|
||||
end, Map),
|
||||
{ldap_vcard_map, NewMap};
|
||||
(Opt) ->
|
||||
Opt
|
||||
end, Opts).
|
||||
|
||||
check_filter(F) ->
|
||||
NewF = iolist_to_binary(F),
|
||||
{ok, _} = eldap_filter:parse(NewF),
|
||||
|
@ -490,13 +490,11 @@ path_to_node(Path) -> node_flat:path_to_node(Path).
|
||||
%% Check that the mod_caps module is enabled in that Jabber Host
|
||||
%% If not, show a warning message in the ejabberd log file.
|
||||
complain_if_modcaps_disabled(ServerHost) ->
|
||||
Modules = ejabberd_config:get_local_option({modules, ServerHost}, fun(Ms) when is_list(Ms) -> Ms end),
|
||||
ModCaps = [mod_caps_enabled || {mod_caps, _Opts} <- Modules],
|
||||
case ModCaps of
|
||||
[] ->
|
||||
case gen_mod:is_loaded(ServerHost, mod_caps) of
|
||||
false ->
|
||||
?WARNING_MSG("The PEP plugin is enabled in mod_pubsub "
|
||||
"of host ~p. This plugin requires mod_caps "
|
||||
"to be enabled, but it isn't.",
|
||||
[ServerHost]);
|
||||
_ -> ok
|
||||
true -> ok
|
||||
end.
|
||||
|
@ -433,7 +433,7 @@ path_to_node(Path) -> node_flat_odbc:path_to_node(Path).
|
||||
%% Check that the mod_caps module is enabled in that Jabber Host
|
||||
%% If not, show a warning message in the ejabberd log file.
|
||||
complain_if_modcaps_disabled(ServerHost) ->
|
||||
Modules = ejabberd_config:get_local_option({modules,
|
||||
Modules = ejabberd_config:get_option({modules,
|
||||
ServerHost},
|
||||
fun(Ms) when is_list(Ms) -> Ms end),
|
||||
ModCaps = [mod_caps_enabled
|
||||
|
@ -219,13 +219,15 @@ list_users(LServer,
|
||||
[Prefix, Limit, Offset]))]).
|
||||
|
||||
users_number(LServer) ->
|
||||
case element(1,
|
||||
ejabberd_config:get_local_option(
|
||||
{odbc_server, LServer}, fun(V) -> V end))
|
||||
of
|
||||
Type = ejabberd_config:get_option({odbc_type, LServer},
|
||||
fun(pgsql) -> pgsql;
|
||||
(mysql) -> mysql;
|
||||
(odbc) -> odbc
|
||||
end, odbc),
|
||||
case Type of
|
||||
pgsql ->
|
||||
case
|
||||
ejabberd_config:get_local_option(
|
||||
ejabberd_config:get_option(
|
||||
{pgsql_users_number_estimate, LServer},
|
||||
fun(V) when is_boolean(V) -> V end,
|
||||
false)
|
||||
|
@ -28,7 +28,8 @@
|
||||
|
||||
-author('alexey@process-one.net').
|
||||
|
||||
-export([new/1, new1/1, update/2]).
|
||||
-export([start/0, new/1, new1/1, update/2,
|
||||
transform_options/1, load_from_config/0]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
@ -37,32 +38,66 @@
|
||||
lastrate = 0.0 :: float(),
|
||||
lasttime = 0 :: integer()}).
|
||||
|
||||
-type maxrate() :: none | #maxrate{}.
|
||||
-record(shaper, {name :: {atom(), global},
|
||||
maxrate :: integer()}).
|
||||
|
||||
-type shaper() :: maxrate() | {maxrate(), integer()}.
|
||||
-type shaper() :: none | #maxrate{}.
|
||||
|
||||
-export_type([shaper/0]).
|
||||
|
||||
-spec new(atom()) -> maxrate().
|
||||
-spec start() -> ok.
|
||||
|
||||
start() ->
|
||||
mnesia:create_table(shaper,
|
||||
[{ram_copies, [node()]},
|
||||
{local_content, true},
|
||||
{attributes, record_info(fields, shaper)}]),
|
||||
mnesia:add_table_copy(shaper, node(), ram_copies),
|
||||
load_from_config(),
|
||||
ok.
|
||||
|
||||
-spec load_from_config() -> ok | {error, any()}.
|
||||
|
||||
load_from_config() ->
|
||||
Shapers = ejabberd_config:get_option(
|
||||
shaper, fun(V) -> V end, []),
|
||||
case mnesia:transaction(
|
||||
fun() ->
|
||||
lists:foreach(
|
||||
fun({Name, MaxRate}) ->
|
||||
mnesia:write(#shaper{name = {Name, global},
|
||||
maxrate = MaxRate})
|
||||
end, Shapers)
|
||||
end) of
|
||||
{atomic, ok} ->
|
||||
ok;
|
||||
Err ->
|
||||
{error, Err}
|
||||
end.
|
||||
|
||||
-spec new(atom()) -> shaper().
|
||||
|
||||
new(none) ->
|
||||
none;
|
||||
new(Name) ->
|
||||
Data = ejabberd_config:get_global_option(
|
||||
{shaper, Name, global},
|
||||
fun({maxrate, R}) when is_integer(R), R>0 ->
|
||||
{maxrate, R};
|
||||
(none) ->
|
||||
none
|
||||
end, none),
|
||||
new1(Data).
|
||||
MaxRate = case ets:lookup(shaper, {Name, global}) of
|
||||
[#shaper{maxrate = R}] ->
|
||||
R;
|
||||
[] ->
|
||||
?WARNING_MSG("Attempt to initialize an "
|
||||
"unspecified shaper '~s'", [Name]),
|
||||
none
|
||||
end,
|
||||
new1(MaxRate).
|
||||
|
||||
-spec new1(none | {maxrate, integer()}) -> maxrate().
|
||||
-spec new1(none | integer()) -> shaper().
|
||||
|
||||
new1(none) -> none;
|
||||
new1({maxrate, MaxRate}) ->
|
||||
new1(MaxRate) ->
|
||||
#maxrate{maxrate = MaxRate, lastrate = 0.0,
|
||||
lasttime = now_to_usec(now())}.
|
||||
|
||||
-spec update(maxrate(), integer()) -> {maxrate(), integer()}.
|
||||
-spec update(shaper(), integer()) -> {shaper(), integer()}.
|
||||
|
||||
update(none, _Size) -> {none, 0};
|
||||
update(#maxrate{} = State, Size) ->
|
||||
@ -84,5 +119,15 @@ update(#maxrate{} = State, Size) ->
|
||||
lasttime = NextNow},
|
||||
Pause}.
|
||||
|
||||
transform_options(Opts) ->
|
||||
lists:foldl(fun transform_options/2, [], Opts).
|
||||
|
||||
transform_options({shaper, Name, {maxrate, N}}, Opts) ->
|
||||
[{shaper, [{Name, N}]}|Opts];
|
||||
transform_options({shaper, Name, none}, Opts) ->
|
||||
[{shaper, [{Name, none}]}|Opts];
|
||||
transform_options(Opt, Opts) ->
|
||||
[Opt|Opts].
|
||||
|
||||
now_to_usec({MSec, Sec, USec}) ->
|
||||
(MSec * 1000000 + Sec) * 1000000 + USec.
|
||||
|
267
test/ejabberd_SUITE_data/ejabberd.yml
Normal file
267
test/ejabberd_SUITE_data/ejabberd.yml
Normal file
@ -0,0 +1,267 @@
|
||||
host_config:
|
||||
"pgsql.localhost":
|
||||
odbc_username: "ejabberd_test"
|
||||
odbc_type: pgsql
|
||||
odbc_server: "localhost"
|
||||
odbc_port: 5432
|
||||
odbc_pool_size: 1
|
||||
odbc_password: "ejabberd_test"
|
||||
odbc_database: "ejabberd_test"
|
||||
auth_method: odbc
|
||||
modules:
|
||||
mod_announce:
|
||||
db_type: odbc
|
||||
mod_blocking:
|
||||
db_type: odbc
|
||||
mod_caps:
|
||||
db_type: odbc
|
||||
mod_last:
|
||||
db_type: odbc
|
||||
mod_muc:
|
||||
db_type: odbc
|
||||
mod_offline:
|
||||
db_type: odbc
|
||||
mod_privacy:
|
||||
db_type: odbc
|
||||
mod_private:
|
||||
db_type: odbc
|
||||
mod_pubsub_odbc:
|
||||
access_createnode: pubsub_createnode
|
||||
ignore_pep_from_offline: true
|
||||
last_item_cache: false
|
||||
plugins:
|
||||
- "flat"
|
||||
- "hometree"
|
||||
- "pep"
|
||||
mod_roster:
|
||||
db_type: odbc
|
||||
mod_mam:
|
||||
db_type: odbc
|
||||
mod_vcard:
|
||||
db_type: odbc
|
||||
mod_adhoc: []
|
||||
mod_configure: []
|
||||
mod_disco: []
|
||||
mod_ping: []
|
||||
mod_proxy65: []
|
||||
mod_register:
|
||||
welcome_message:
|
||||
subject: "Welcome!"
|
||||
body: "Hi.
|
||||
Welcome to this XMPP server."
|
||||
mod_stats: []
|
||||
mod_time: []
|
||||
mod_version: []
|
||||
host_config:
|
||||
"mysql.localhost":
|
||||
odbc_username: "ejabberd_test"
|
||||
odbc_type: mysql
|
||||
odbc_server: "localhost"
|
||||
odbc_port: 3306
|
||||
odbc_pool_size: 1
|
||||
odbc_password: "ejabberd_test"
|
||||
odbc_database: "ejabberd_test"
|
||||
auth_method: odbc
|
||||
modules:
|
||||
mod_announce:
|
||||
db_type: odbc
|
||||
mod_blocking:
|
||||
db_type: odbc
|
||||
mod_caps:
|
||||
db_type: odbc
|
||||
mod_last:
|
||||
db_type: odbc
|
||||
mod_muc:
|
||||
db_type: odbc
|
||||
mod_offline:
|
||||
db_type: odbc
|
||||
mod_privacy:
|
||||
db_type: odbc
|
||||
mod_private:
|
||||
db_type: odbc
|
||||
mod_pubsub_odbc:
|
||||
access_createnode: pubsub_createnode
|
||||
ignore_pep_from_offline: true
|
||||
last_item_cache: false
|
||||
plugins:
|
||||
- "flat"
|
||||
- "hometree"
|
||||
- "pep"
|
||||
mod_roster:
|
||||
db_type: odbc
|
||||
mod_mam:
|
||||
db_type: odbc
|
||||
mod_vcard:
|
||||
db_type: odbc
|
||||
mod_adhoc: []
|
||||
mod_configure: []
|
||||
mod_disco: []
|
||||
mod_ping: []
|
||||
mod_proxy65: []
|
||||
mod_register:
|
||||
welcome_message:
|
||||
subject: "Welcome!"
|
||||
body: "Hi.
|
||||
Welcome to this XMPP server."
|
||||
mod_stats: []
|
||||
mod_time: []
|
||||
mod_version: []
|
||||
host_config:
|
||||
"mnesia.localhost":
|
||||
auth_method: internal
|
||||
modules:
|
||||
mod_announce:
|
||||
db_type: internal
|
||||
mod_blocking:
|
||||
db_type: internal
|
||||
mod_caps:
|
||||
db_type: internal
|
||||
mod_last:
|
||||
db_type: internal
|
||||
mod_muc:
|
||||
db_type: internal
|
||||
mod_offline:
|
||||
db_type: internal
|
||||
mod_privacy:
|
||||
db_type: internal
|
||||
mod_private:
|
||||
db_type: internal
|
||||
mod_pubsub:
|
||||
access_createnode: pubsub_createnode
|
||||
ignore_pep_from_offline: true
|
||||
last_item_cache: false
|
||||
plugins:
|
||||
- "flat"
|
||||
- "hometree"
|
||||
- "pep"
|
||||
mod_roster:
|
||||
db_type: internal
|
||||
mod_mam:
|
||||
db_type: internal
|
||||
mod_vcard:
|
||||
db_type: internal
|
||||
mod_adhoc: []
|
||||
mod_configure: []
|
||||
mod_disco: []
|
||||
mod_ping: []
|
||||
mod_proxy65: []
|
||||
mod_register:
|
||||
welcome_message:
|
||||
subject: "Welcome!"
|
||||
body: "Hi.
|
||||
Welcome to this XMPP server."
|
||||
mod_stats: []
|
||||
mod_time: []
|
||||
mod_version: []
|
||||
host_config:
|
||||
"localhost":
|
||||
auth_method: internal
|
||||
host_config:
|
||||
"ldap.localhost":
|
||||
ldap_servers:
|
||||
- "localhost"
|
||||
ldap_rootdn: "cn=admin,dc=localhost"
|
||||
ldap_port: 1389
|
||||
ldap_password: "password"
|
||||
ldap_base: "ou=users,dc=localhost"
|
||||
auth_method: ldap
|
||||
modules:
|
||||
mod_vcard_ldap: []
|
||||
mod_adhoc: []
|
||||
mod_configure: []
|
||||
mod_disco: []
|
||||
mod_ping: []
|
||||
mod_proxy65: []
|
||||
mod_register:
|
||||
welcome_message:
|
||||
subject: "Welcome!"
|
||||
body: "Hi.
|
||||
Welcome to this XMPP server."
|
||||
mod_stats: []
|
||||
mod_time: []
|
||||
mod_version: []
|
||||
host_config:
|
||||
"extauth.localhost":
|
||||
extauth_program: "python extauth.py"
|
||||
auth_method: external
|
||||
hosts:
|
||||
- "localhost"
|
||||
- "mnesia.localhost"
|
||||
- "mysql.localhost"
|
||||
- "pgsql.localhost"
|
||||
- "extauth.localhost"
|
||||
- "ldap.localhost"
|
||||
access:
|
||||
announce:
|
||||
admin: allow
|
||||
c2s:
|
||||
blocked: deny
|
||||
all: allow
|
||||
c2s_shaper:
|
||||
admin: none
|
||||
all: normal
|
||||
configure:
|
||||
admin: allow
|
||||
local:
|
||||
local: allow
|
||||
max_user_offline_messages:
|
||||
admin: 5000
|
||||
all: 100
|
||||
max_user_sessions:
|
||||
all: 10
|
||||
muc:
|
||||
all: allow
|
||||
muc_admin:
|
||||
admin: allow
|
||||
muc_create:
|
||||
local: allow
|
||||
pubsub_createnode:
|
||||
local: allow
|
||||
register:
|
||||
all: allow
|
||||
s2s_shaper:
|
||||
all: fast
|
||||
acl:
|
||||
local:
|
||||
user_regexp:
|
||||
- []
|
||||
define_macro:
|
||||
CERTFILE: "cert.pem"
|
||||
language: "en"
|
||||
listen:
|
||||
-
|
||||
port: 5222
|
||||
module: ejabberd_c2s
|
||||
max_stanza_size: 65536
|
||||
certfile: CERTFILE
|
||||
zlib: true
|
||||
starttls: true
|
||||
shaper: c2s_shaper
|
||||
access: c2s
|
||||
-
|
||||
port: 5269
|
||||
module: ejabberd_s2s_in
|
||||
-
|
||||
port: 5280
|
||||
module: ejabberd_http
|
||||
captcha: true
|
||||
loglevel: 4
|
||||
max_fsm_queue: 1000
|
||||
modules:
|
||||
mod_adhoc: []
|
||||
mod_configure: []
|
||||
mod_disco: []
|
||||
mod_ping: []
|
||||
mod_proxy65: []
|
||||
mod_register:
|
||||
welcome_message:
|
||||
subject: "Welcome!"
|
||||
body: "Hi.
|
||||
Welcome to this XMPP server."
|
||||
mod_stats: []
|
||||
mod_time: []
|
||||
mod_version: []
|
||||
registration_timeout: infinity
|
||||
shaper:
|
||||
fast: 50000
|
||||
normal: 1000
|
@ -21,7 +21,7 @@ init_config(Config) ->
|
||||
PrivDir = proplists:get_value(priv_dir, Config),
|
||||
[_, _|Tail] = lists:reverse(filename:split(DataDir)),
|
||||
BaseDir = filename:join(lists:reverse(Tail)),
|
||||
ConfigPath = filename:join([DataDir, "ejabberd.cfg"]),
|
||||
ConfigPath = filename:join([DataDir, "ejabberd.yml"]),
|
||||
LogPath = filename:join([PrivDir, "ejabberd.log"]),
|
||||
SASLPath = filename:join([PrivDir, "sasl.log"]),
|
||||
MnesiaDir = filename:join([PrivDir, "mnesia"]),
|
||||
|
Loading…
Reference in New Issue
Block a user