summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.in1
-rw-r--r--configure.ac1
-rwxr-xr-xejabberdctl.template29
-rw-r--r--mix.exs2
-rw-r--r--mix.lock8
-rw-r--r--rebar.config6
-rw-r--r--sql/mysql.sql2
-rw-r--r--src/ejabberd_auth.erl25
-rw-r--r--src/ejabberd_auth_external.erl42
-rw-r--r--src/ejabberd_auth_mnesia.erl (renamed from src/ejabberd_auth_internal.erl)4
-rw-r--r--src/ejabberd_c2s.erl1
-rw-r--r--src/ejabberd_config.erl136
-rw-r--r--src/ejabberd_ctl.erl2
-rw-r--r--src/ejabberd_riak_sup.erl4
-rw-r--r--src/ejabberd_sm.erl24
-rw-r--r--src/ejd2sql.erl2
-rw-r--r--src/gen_mod.erl61
-rw-r--r--src/mod_announce.erl2
-rw-r--r--src/mod_caps.erl2
-rw-r--r--src/mod_carboncopy.erl5
-rw-r--r--src/mod_irc.erl2
-rw-r--r--src/mod_last.erl2
-rw-r--r--src/mod_mam.erl11
-rw-r--r--src/mod_metrics.erl5
-rw-r--r--src/mod_muc.erl2
-rw-r--r--src/mod_offline.erl2
-rw-r--r--src/mod_privacy.erl2
-rw-r--r--src/mod_private.erl2
-rw-r--r--src/mod_pubsub.erl31
-rw-r--r--src/mod_roster.erl2
-rw-r--r--src/mod_shared_roster.erl2
-rw-r--r--src/mod_vcard.erl2
-rw-r--r--src/mod_vcard_xupdate.erl2
-rw-r--r--src/mod_vcard_xupdate_riak.erl2
-rw-r--r--src/mod_vcard_xupdate_sql.erl2
-rw-r--r--src/shaper.erl6
-rw-r--r--test/ejabberd_SUITE.erl90
-rw-r--r--test/ejabberd_SUITE_data/ejabberd.yml2
-rw-r--r--test/suite.erl1
-rw-r--r--tools/xmpp_codec.erl9
-rw-r--r--tools/xmpp_codec.spec6
-rw-r--r--vars.config.in1
42 files changed, 367 insertions, 178 deletions
diff --git a/Makefile.in b/Makefile.in
index 0d913448..b08eb444 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -185,6 +185,7 @@ install: all copy-files
-e "s*{{localstatedir}}*@localstatedir@*" \
-e "s*{{docdir}}*@docdir@*" \
-e "s*{{erl}}*@ERL@*" ejabberdctl.template \
+ -e "s*{{epmd}}*@EPMD@*" ejabberdctl.template \
> ejabberdctl.example
[ -f $(ETCDIR)/ejabberdctl.cfg ] \
&& $(INSTALL) -b -m 640 $(G_USER) ejabberdctl.cfg.example $(ETCDIR)/ejabberdctl.cfg-new \
diff --git a/configure.ac b/configure.ac
index e5d92c89..f3ff9ae5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -30,6 +30,7 @@ fi
AC_PATH_TOOL(ERL, erl, , [${extra_erl_path}$PATH])
AC_PATH_TOOL(ERLC, erlc, , [${extra_erl_path}$PATH])
+AC_PATH_TOOL(EPMD, epmd, , [${extra_erl_path}$PATH])
AC_ERLANG_NEED_ERL
AC_ERLANG_NEED_ERLC
diff --git a/ejabberdctl.template b/ejabberdctl.template
index 224650fe..7a3b589b 100755
--- a/ejabberdctl.template
+++ b/ejabberdctl.template
@@ -13,7 +13,7 @@ ERLANG_NODE=ejabberd@localhost
SCRIPT_DIR=`cd ${0%/*} && pwd`
ERL={{erl}}
IEX={{bindir}}/iex
-EPMD={{bindir}}/epmd
+EPMD={{epmd}}
INSTALLUSER={{installuser}}
ERL_LIBS={{libdir}}
@@ -83,18 +83,9 @@ if [ "$EJABBERD_DOC_PATH" = "" ] ; then
fi
if [ "$ERLANG_NODE_ARG" != "" ] ; then
ERLANG_NODE=$ERLANG_NODE_ARG
- NODE=${ERLANG_NODE%@*}
fi
-if [ "{{release}}" != "true" ] ; then
- if [ "$EJABBERDDIR" = "" ] ; then
- EJABBERDDIR={{libdir}}/ejabberd
- fi
- if [ "$EJABBERD_PRIV_PATH" = "" ] ; then
- EJABBERD_PRIV_PATH=$EJABBERDDIR/priv
- fi
- if [ "$EJABBERD_BIN_PATH" = "" ] ; then
- EJABBERD_BIN_PATH=$EJABBERD_PRIV_PATH/bin
- fi
+if [ "{{release}}" != "true" -a "$EJABBERD_BIN_PATH" = "" ] ; then
+ EJABBERD_BIN_PATH={{libdir}}/ejabberd/priv/bin
fi
EJABBERD_LOG_PATH=$LOGS_DIR/ejabberd.log
DATETIME=`date "+%Y%m%d-%H%M%S"`
@@ -141,8 +132,8 @@ fi
[ -z "$date" ] || EJABBERD_OPTS="${EJABBERD_OPTS} log_rotate_date '$date'"
[ -z "$EJABBERD_OPTS" ] || EJABBERD_OPTS="-ejabberd ${EJABBERD_OPTS}"
-[ -d $SPOOL_DIR ] || $EXEC_CMD "mkdir -p $SPOOL_DIR"
-cd $SPOOL_DIR
+[ -d "$SPOOL_DIR" ] || $EXEC_CMD "mkdir -p $SPOOL_DIR"
+cd "$SPOOL_DIR"
# export global variables
export EJABBERD_CONFIG_PATH
@@ -221,7 +212,7 @@ iexdebug()
--erl `shell_escape \"$ERLANG_OPTS\"` \
--erl `shell_escape \"${ARGS[@]}\"` \
--erl `shell_escape_str \"$@\"`"
- $EXEC_CMD "$CMD"
+ $EXEC_CMD "ERL_PATH=$\"$ERL\" $CMD"
}
# start interactive server
@@ -251,7 +242,7 @@ iexlive()
--erl `shell_escape \"$ERLANG_OPTS\"` \
--erl `shell_escape \"${ARGS[@]}\"` \
--erl `shell_escape_str \"$@\"`"
- $EXEC_CMD "$CMD"
+ $EXEC_CMD "ERL_PATH=\"$ERL\" $CMD"
}
# start server in the foreground
@@ -396,13 +387,13 @@ uid()
# stop epmd if there is no other running node
stop_epmd()
{
- $EPMD -names 2>/dev/null | grep -q name || $EPMD -kill >/dev/null
+ "$EPMD" -names 2>/dev/null | grep -q name || "$EPMD" -kill >/dev/null
}
# make sure node not already running and node name unregistered
check_start()
{
- $EPMD -names 2>/dev/null | grep -q " ${ERLANG_NODE%@*} " && {
+ "$EPMD" -names 2>/dev/null | grep -q " ${ERLANG_NODE%@*} " && {
ps ux | grep -v grep | grep -q " $ERLANG_NODE " && {
echo "ERROR: The ejabberd node '$ERLANG_NODE' is already running."
exit 4
@@ -413,7 +404,7 @@ check_start()
echo "Shutdown all other erlang nodes, and call 'epmd -kill'."
exit 5
} || {
- $EPMD -kill >/dev/null
+ "$EPMD" -kill >/dev/null
}
}
}
diff --git a/mix.exs b/mix.exs
index 8f58e677..577706eb 100644
--- a/mix.exs
+++ b/mix.exs
@@ -3,7 +3,7 @@ defmodule Ejabberd.Mixfile do
def project do
[app: :ejabberd,
- version: "16.03.0",
+ version: "16.04.0",
description: description,
elixir: "~> 1.2",
elixirc_paths: ["lib"],
diff --git a/mix.lock b/mix.lock
index 6cc41bba..45cfb0a7 100644
--- a/mix.lock
+++ b/mix.lock
@@ -3,10 +3,10 @@
"cf": {:hex, :cf, "0.2.1"},
"eredis": {:hex, :eredis, "1.0.8"},
"erlware_commons": {:hex, :erlware_commons, "0.19.0"},
- "esip": {:hex, :esip, "1.0.2"},
+ "esip": {:hex, :esip, "1.0.4"},
"exrm": {:hex, :exrm, "1.0.3"},
"ezlib": {:hex, :ezlib, "1.0.1"},
- "fast_tls": {:hex, :fast_tls, "1.0.1"},
+ "fast_tls": {:hex, :fast_tls, "1.0.3"},
"fast_xml": {:hex, :fast_xml, "1.1.11"},
"fast_yaml": {:hex, :fast_yaml, "1.0.3"},
"getopt": {:hex, :getopt, "0.8.2"},
@@ -20,7 +20,7 @@
"p1_utils": {:hex, :p1_utils, "1.0.3"},
"p1_xmlrpc": {:hex, :p1_xmlrpc, "1.15.1"},
"providers": {:hex, :providers, "1.6.0"},
- "relx": {:hex, :relx, "3.18.0"},
+ "relx": {:hex, :relx, "3.19.0"},
"sqlite3": {:hex, :sqlite3, "1.1.5"},
"stringprep": {:hex, :stringprep, "1.0.3"},
- "stun": {:hex, :stun, "1.0.1"}}
+ "stun": {:hex, :stun, "1.0.3"}}
diff --git a/rebar.config b/rebar.config
index d006dc64..dfce7075 100644
--- a/rebar.config
+++ b/rebar.config
@@ -10,11 +10,11 @@
{deps, [{lager, ".*", {git, "https://github.com/basho/lager", {tag, "3.0.2"}}},
{p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.4"}}},
{cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.2"}}},
- {fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.1"}}},
+ {fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.3"}}},
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.3"}}},
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.3"}}},
- {stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.1"}}},
- {esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.2"}}},
+ {stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.3"}}},
+ {esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.4"}}},
{fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.3"}}},
{jiffy, ".*", {git, "https://github.com/davisp/jiffy", {tag, "0.14.7"}}},
{p1_oauth2, ".*", {git, "https://github.com/processone/p1_oauth2", {tag, "0.6.1"}}},
diff --git a/sql/mysql.sql b/sql/mysql.sql
index b7a86d0e..5150fc45 100644
--- a/sql/mysql.sql
+++ b/sql/mysql.sql
@@ -275,7 +275,7 @@ CREATE UNIQUE INDEX i_pubsub_subscription_opt ON pubsub_subscription_opt(subid(3
CREATE TABLE muc_room (
name text NOT NULL,
host text NOT NULL,
- opts text NOT NULL,
+ opts mediumtext NOT NULL,
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl
index 0267a219..6b7f537c 100644
--- a/src/ejabberd_auth.erl
+++ b/src/ejabberd_auth.erl
@@ -136,7 +136,7 @@ check_password(User, AuthzId, Server, Password, Digest,
%% {true, AuthModule} | false
%% where
%% AuthModule = ejabberd_auth_anonymous | ejabberd_auth_external
-%% | ejabberd_auth_internal | ejabberd_auth_ldap
+%% | ejabberd_auth_mnesia | ejabberd_auth_ldap
%% | ejabberd_auth_sql | ejabberd_auth_pam | ejabberd_auth_riak
-spec check_password_with_authmodule(binary(), binary(), binary(), binary()) -> false |
{true, atom()}.
@@ -428,30 +428,21 @@ auth_modules() ->
%% Return the list of authenticated modules for a given host
auth_modules(Server) ->
LServer = jid:nameprep(Server),
- Default = case gen_mod:default_db(LServer) of
- mnesia -> internal;
- DBType -> DBType
- end,
+ Default = ejabberd_config:default_db(LServer, ?MODULE),
Methods = ejabberd_config:get_option(
- {auth_method, LServer},
- fun(V) when is_list(V) ->
- true = lists:all(fun is_atom/1, V),
- V;
- (V) when is_atom(V) ->
- [V]
- end, [Default]),
+ {auth_method, LServer}, opt_type(auth_method), [Default]),
[jlib:binary_to_atom(<<"ejabberd_auth_",
(jlib:atom_to_binary(M))/binary>>)
|| M <- Methods].
export(Server) ->
- ejabberd_auth_internal:export(Server).
+ ejabberd_auth_mnesia:export(Server).
import(Server) ->
- ejabberd_auth_internal:import(Server).
+ ejabberd_auth_mnesia:import(Server).
import(Server, mnesia, Passwd) ->
- ejabberd_auth_internal:import(Server, mnesia, Passwd);
+ ejabberd_auth_mnesia:import(Server, mnesia, Passwd);
import(Server, riak, Passwd) ->
ejabberd_auth_riak:import(Server, riak, Passwd);
import(_, _, _) ->
@@ -459,7 +450,7 @@ import(_, _, _) ->
opt_type(auth_method) ->
fun (V) when is_list(V) ->
- true = lists:all(fun is_atom/1, V), V;
- (V) when is_atom(V) -> [V]
+ lists:map(fun(M) -> ejabberd_config:v_db(?MODULE, M) end, V);
+ (V) -> [ejabberd_config:v_db(?MODULE, V)]
end;
opt_type(_) -> [auth_method].
diff --git a/src/ejabberd_auth_external.erl b/src/ejabberd_auth_external.erl
index 5897fba5..ef7c9755 100644
--- a/src/ejabberd_auth_external.erl
+++ b/src/ejabberd_auth_external.erl
@@ -56,7 +56,7 @@ start(Host) ->
"extauth"),
extauth:start(Host, Cmd),
check_cache_last_options(Host),
- ejabberd_auth_internal:start(Host).
+ ejabberd_auth_mnesia:start(Host).
check_cache_last_options(Server) ->
case get_cache_option(Server) of
@@ -94,7 +94,7 @@ check_password(User, AuthzId, Server, Password, _Digest,
set_password(User, Server, Password) ->
case extauth:set_password(User, Server, Password) of
true ->
- set_password_internal(User, Server, Password), ok;
+ set_password_mnesia(User, Server, Password), ok;
_ -> {error, unknown_problem}
end.
@@ -106,20 +106,20 @@ try_register(User, Server, Password) ->
end.
dirty_get_registered_users() ->
- ejabberd_auth_internal:dirty_get_registered_users().
+ ejabberd_auth_mnesia:dirty_get_registered_users().
get_vh_registered_users(Server) ->
- ejabberd_auth_internal:get_vh_registered_users(Server).
+ ejabberd_auth_mnesia:get_vh_registered_users(Server).
get_vh_registered_users(Server, Data) ->
- ejabberd_auth_internal:get_vh_registered_users(Server,
+ ejabberd_auth_mnesia:get_vh_registered_users(Server,
Data).
get_vh_registered_users_number(Server) ->
- ejabberd_auth_internal:get_vh_registered_users_number(Server).
+ ejabberd_auth_mnesia:get_vh_registered_users_number(Server).
get_vh_registered_users_number(Server, Data) ->
- ejabberd_auth_internal:get_vh_registered_users_number(Server,
+ ejabberd_auth_mnesia:get_vh_registered_users_number(Server,
Data).
%% The password can only be returned if cache is enabled, cached info exists and is fresh enough.
@@ -151,7 +151,7 @@ remove_user(User, Server) ->
case get_cache_option(Server) of
false -> false;
{true, _CacheTime} ->
- ejabberd_auth_internal:remove_user(User, Server)
+ ejabberd_auth_mnesia:remove_user(User, Server)
end
end.
@@ -162,7 +162,7 @@ remove_user(User, Server, Password) ->
case get_cache_option(Server) of
false -> false;
{true, _CacheTime} ->
- ejabberd_auth_internal:remove_user(User, Server,
+ ejabberd_auth_mnesia:remove_user(User, Server,
Password)
end
end.
@@ -197,7 +197,7 @@ check_password_cache(User, AuthzId, Server, Password,
CacheTime) ->
case get_last_access(User, Server) of
online ->
- check_password_internal(User, AuthzId, Server, Password);
+ check_password_mnesia(User, AuthzId, Server, Password);
never ->
check_password_external_cache(User, AuthzId, Server, Password);
mod_last_required ->
@@ -210,7 +210,7 @@ check_password_cache(User, AuthzId, Server, Password,
case is_fresh_enough(TimeStamp, CacheTime) of
%% If no need to refresh, check password against Mnesia
true ->
- case check_password_internal(User, AuthzId, Server, Password) of
+ case check_password_mnesia(User, AuthzId, Server, Password) of
%% If password valid in Mnesia, accept it
true -> true;
%% Else (password nonvalid in Mnesia), check in extauth and cache result
@@ -223,13 +223,13 @@ check_password_cache(User, AuthzId, Server, Password,
end
end.
-get_password_internal(User, Server) ->
- ejabberd_auth_internal:get_password(User, Server).
+get_password_mnesia(User, Server) ->
+ ejabberd_auth_mnesia:get_password(User, Server).
-spec get_password_cache(User::binary(), Server::binary(), CacheTime::integer()) -> Password::string() | false.
get_password_cache(User, Server, CacheTime) ->
case get_last_access(User, Server) of
- online -> get_password_internal(User, Server);
+ online -> get_password_mnesia(User, Server);
never -> false;
mod_last_required ->
?ERROR_MSG("extauth is used, extauth_cache is enabled "
@@ -239,7 +239,7 @@ get_password_cache(User, Server, CacheTime) ->
false;
TimeStamp ->
case is_fresh_enough(TimeStamp, CacheTime) of
- true -> get_password_internal(User, Server);
+ true -> get_password_mnesia(User, Server);
false -> false
end
end.
@@ -248,7 +248,7 @@ get_password_cache(User, Server, CacheTime) ->
check_password_external_cache(User, AuthzId, Server, Password) ->
case check_password_extauth(User, AuthzId, Server, Password) of
true ->
- set_password_internal(User, Server, Password), true;
+ set_password_mnesia(User, Server, Password), true;
false -> false
end.
@@ -256,21 +256,21 @@ check_password_external_cache(User, AuthzId, Server, Password) ->
try_register_external_cache(User, Server, Password) ->
case try_register_extauth(User, Server, Password) of
{atomic, ok} = R ->
- set_password_internal(User, Server, Password), R;
+ set_password_mnesia(User, Server, Password), R;
_ -> {error, not_allowed}
end.
%% @spec (User, AuthzId, Server, Password) -> true | false
-check_password_internal(User, AuthzId, Server, Password) ->
- ejabberd_auth_internal:check_password(User, AuthzId, Server,
+check_password_mnesia(User, AuthzId, Server, Password) ->
+ ejabberd_auth_mnesia:check_password(User, AuthzId, Server,
Password).
%% @spec (User, Server, Password) -> ok | {error, invalid_jid}
-set_password_internal(User, Server, Password) ->
+set_password_mnesia(User, Server, Password) ->
%% @spec (TimeLast, CacheTime) -> true | false
%% TimeLast = online | never | integer()
%% CacheTime = integer() | false
- ejabberd_auth_internal:set_password(User, Server,
+ ejabberd_auth_mnesia:set_password(User, Server,
Password).
is_fresh_enough(TimeStampLast, CacheTime) ->
diff --git a/src/ejabberd_auth_internal.erl b/src/ejabberd_auth_mnesia.erl
index acbbfe50..9029404d 100644
--- a/src/ejabberd_auth_internal.erl
+++ b/src/ejabberd_auth_mnesia.erl
@@ -1,5 +1,5 @@
%%%----------------------------------------------------------------------
-%%% File : ejabberd_auth_internal.erl
+%%% File : ejabberd_auth_mnesia.erl
%%% Author : Alexey Shchepin <alexey@process-one.net>
%%% Purpose : Authentification via mnesia
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
@@ -23,7 +23,7 @@
%%%
%%%----------------------------------------------------------------------
--module(ejabberd_auth_internal).
+-module(ejabberd_auth_mnesia).
-behaviour(ejabberd_config).
diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl
index 948e2027..e75cb0ab 100644
--- a/src/ejabberd_c2s.erl
+++ b/src/ejabberd_c2s.erl
@@ -1613,7 +1613,6 @@ handle_info({route, From, To,
<<"error">> -> ok;
<<"groupchat">> -> ok;
<<"headline">> -> ok;
- <<"result">> -> ok;
_ ->
Err =
jlib:make_error_reply(Packet,
diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl
index f73474fe..06de61b5 100644
--- a/src/ejabberd_config.erl
+++ b/src/ejabberd_config.erl
@@ -34,8 +34,8 @@
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,
+ transform_options/1, collect_options/1, default_db/2,
+ convert_to_yaml/1, convert_to_yaml/2, v_db/2,
env_binary_to_list/2, opt_type/1, may_hide_data/1]).
-export([start/2]).
@@ -227,6 +227,7 @@ 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),
+ DontStopOnError = lists:member(dont_halt_on_error, Opts),
case consult(File) of
{ok, Terms} ->
BinTerms1 = strings_to_binary(Terms),
@@ -246,9 +247,21 @@ get_plain_terms_file(File1, Opts) ->
false ->
BinTerms
end;
- {error, Reason} ->
+ {error, enoent, Reason} ->
+ case DontStopOnError of
+ true ->
+ ?WARNING_MSG(Reason, []),
+ [];
+ _ ->
?ERROR_MSG(Reason, []),
exit_or_halt(Reason)
+ end;
+ {error, Reason} ->
+ ?ERROR_MSG(Reason, []),
+ case DontStopOnError of
+ true -> [];
+ _ -> exit_or_halt(Reason)
+ end
end.
consult(File) ->
@@ -262,17 +275,29 @@ consult(File) ->
{error, Err} ->
Msg1 = "Cannot load " ++ File ++ ": ",
Msg2 = fast_yaml:format_error(Err),
+ case Err of
+ enoent ->
+ {error, enoent, Msg1 ++ Msg2};
+ _ ->
{error, Msg1 ++ Msg2}
+ end
end;
_ ->
case file:consult(File) of
{ok, Terms} ->
{ok, Terms};
+ {error, enoent} ->
+ {error, enoent};
{error, {LineNumber, erl_parse, _ParseMessage} = Reason} ->
{error, describe_config_problem(File, Reason, LineNumber)};
{error, Reason} ->
+ case Reason of
+ enoent ->
+ {error, enoent, describe_config_problem(File, Reason)};
+ _ ->
{error, describe_config_problem(File, Reason)}
end
+ end
end.
parserl(<<"> ", Term/binary>>) ->
@@ -488,7 +513,7 @@ transform_include_option({include_config_file, Filename, Options}) ->
{Filename, Options}.
include_config_file(Filename, Options) ->
- Included_terms = get_plain_terms_file(Filename),
+ Included_terms = get_plain_terms_file(Filename, [{include_files, true}, dont_halt_on_error]),
Disallow = proplists:get_value(disallow, Options, []),
Included_terms2 = delete_disallowed(Disallow, Included_terms),
Allow_only = proplists:get_value(allow_only, Options, all),
@@ -651,9 +676,9 @@ process_host_term(Term, Host, State, Action) ->
{hosts, _} ->
State;
{Opt, Val} when Action == set ->
- set_option({rename_option(Opt), Host}, Val, State);
+ set_option({rename_option(Opt), Host}, change_val(Opt, Val), State);
{Opt, Val} when Action == append ->
- append_option({rename_option(Opt), Host}, Val, State);
+ append_option({rename_option(Opt), Host}, change_val(Opt, Val), State);
Opt ->
?WARNING_MSG("Ignore invalid (outdated?) option ~p", [Opt]),
State
@@ -672,6 +697,21 @@ rename_option(Option) when is_atom(Option) ->
rename_option(Option) ->
Option.
+change_val(auth_method, Val) ->
+ prepare_opt_val(auth_method, Val,
+ fun(V) ->
+ L = if is_list(V) -> V;
+ true -> [V]
+ end,
+ lists:map(
+ fun(odbc) -> sql;
+ (internal) -> mnesia;
+ (A) when is_atom(A) -> A
+ end, L)
+ end, [mnesia]);
+change_val(_Opt, Val) ->
+ Val.
+
set_option(Opt, Val, State) ->
State#state{opts = [#local_config{key = Opt, value = Val} |
State#state.opts]}.
@@ -738,13 +778,11 @@ prepare_opt_val(Opt, Val, F, Default) ->
end,
case Res of
{'EXIT', _} ->
- ?INFO_MSG("Configuration problem:~n"
- "** Option: ~s~n"
- "** Invalid value: ~s~n"
- "** Using as fallback: ~s",
- [format_term(Opt),
- format_term(Val),
- format_term(Default)]),
+ ?WARNING_MSG("incorrect value '~s' of option '~s', "
+ "using '~s' as fallback",
+ [format_term(Val),
+ format_term(Opt),
+ format_term(Default)]),
Default;
_ ->
Res
@@ -800,9 +838,57 @@ get_option(Opt, F, Default) ->
end
end.
+init_module_db_table(Modules) ->
+ catch ets:new(module_db, [named_table, public, bag]),
+ %% Dirty hack for mod_pubsub
+ ets:insert(module_db, {mod_pubsub, mnesia}),
+ ets:insert(module_db, {mod_pubsub, sql}),
+ lists:foreach(
+ fun(M) ->
+ case re:split(atom_to_list(M), "_", [{return, list}]) of
+ [_] ->
+ ok;
+ Parts ->
+ [Suffix|T] = lists:reverse(Parts),
+ BareMod = string:join(lists:reverse(T), "_"),
+ ets:insert(module_db, {list_to_atom(BareMod),
+ list_to_atom(Suffix)})
+ end
+ end, Modules).
+
+-spec v_db(module(), atom()) -> atom().
+
+v_db(Mod, internal) -> v_db(Mod, mnesia);
+v_db(Mod, odbc) -> v_db(Mod, sql);
+v_db(Mod, Type) ->
+ case ets:match_object(module_db, {Mod, Type}) of
+ [_|_] -> Type;
+ [] -> erlang:error(badarg)
+ end.
+
+-spec default_db(binary(), module()) -> atom().
+
+default_db(Host, Module) ->
+ case ejabberd_config:get_option(
+ {default_db, Host}, fun(T) when is_atom(T) -> T end) of
+ undefined ->
+ mnesia;
+ DBType ->
+ try
+ v_db(Module, DBType)
+ catch error:badarg ->
+ ?WARNING_MSG("Module '~s' doesn't support database '~s' "
+ "defined in option 'default_db', using "
+ "'mnesia' as fallback", [Module, DBType]),
+ mnesia
+ end
+ end.
+
get_modules_with_options() ->
{ok, Mods} = application:get_key(ejabberd, modules),
ExtMods = [Name || {Name, _Details} <- ext_mod:installed()],
+ AllMods = [?MODULE|ExtMods++Mods],
+ init_module_db_table(AllMods),
lists:foldl(
fun(Mod, D) ->
case catch Mod:opt_type('') of
@@ -814,7 +900,7 @@ get_modules_with_options() ->
{'EXIT', {undef, _}} ->
D
end
- end, dict:new(), [?MODULE|ExtMods++Mods]).
+ end, dict:new(), AllMods).
validate_opts(#state{opts = Opts} = State) ->
ModOpts = get_modules_with_options(),
@@ -842,11 +928,25 @@ validate_opts(#state{opts = Opts} = State) ->
-spec get_vh_by_auth_method(atom()) -> [binary()].
-%% Return the list of hosts handled by a given module
+%% Return the list of hosts with a given auth method
get_vh_by_auth_method(AuthMethod) ->
- mnesia:dirty_select(local_config,
- [{#local_config{key = {auth_method, '$1'},
- value=AuthMethod},[],['$1']}]).
+ Cfgs = mnesia:dirty_match_object(local_config,
+ #local_config{key = {auth_method, '_'},
+ _ = '_'}),
+ lists:flatmap(
+ fun(#local_config{key = {auth_method, Host}, value = M}) ->
+ Methods = if not is_list(M) -> [M];
+ true -> M
+ end,
+ case lists:member(AuthMethod, Methods) of
+ true when Host == global ->
+ get_myhosts();
+ true ->
+ [Host];
+ false ->
+ []
+ end
+ end, Cfgs).
%% @spec (Path::string()) -> true | false
is_file_readable(Path) ->
diff --git a/src/ejabberd_ctl.erl b/src/ejabberd_ctl.erl
index bb16e91e..d52d1c0a 100644
--- a/src/ejabberd_ctl.erl
+++ b/src/ejabberd_ctl.erl
@@ -239,7 +239,7 @@ process2(["--auth", User, Server, Pass | Args], AccessCommands, Version) ->
process2(Args, AccessCommands, {list_to_binary(User), list_to_binary(Server),
list_to_binary(Pass), true}, Version);
process2(Args, AccessCommands, Version) ->
- process2(Args, AccessCommands, admin, Version).
+ process2(Args, AccessCommands, noauth, Version).
diff --git a/src/ejabberd_riak_sup.erl b/src/ejabberd_riak_sup.erl
index af811441..ad65ecf8 100644
--- a/src/ejabberd_riak_sup.erl
+++ b/src/ejabberd_riak_sup.erl
@@ -70,8 +70,8 @@ is_riak_configured(Host) ->
{modules, Host},
fun(L) when is_list(L) -> L end, []),
ModuleWithRiakDBConfigured = lists:any(
- fun({_Module, Opts}) ->
- gen_mod:db_type(Host, Opts) == riak
+ fun({Module, Opts}) ->
+ gen_mod:db_type(Host, Opts, Module) == riak
end, Modules),
ServerConfigured or PortConfigured
or AuthConfigured or ModuleWithRiakDBConfigured.
diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl
index 219d46ad..25f6ea02 100644
--- a/src/ejabberd_sm.erl
+++ b/src/ejabberd_sm.erl
@@ -500,7 +500,7 @@ do_route(From, To, #xmlel{} = Packet) ->
<<"headline">> -> route_message(From, To, Packet, headline);
<<"error">> -> ok;
<<"groupchat">> ->
- ErrTxt = <<"Incorrect message type">>,
+ ErrTxt = <<"User session not found">>,
Err = jlib:make_error_reply(
Packet, ?ERRT_SERVICE_UNAVAILABLE(Lang, ErrTxt)),
ejabberd_router:route(To, From, Err);
@@ -520,9 +520,10 @@ do_route(From, To, #xmlel{} = Packet) ->
<<"chat">> -> route_message(From, To, Packet, chat);
<<"normal">> -> route_message(From, To, Packet, normal);
<<"">> -> route_message(From, To, Packet, normal);
+ <<"headline">> -> ok;
<<"error">> -> ok;
_ ->
- ErrTxt = <<"Incorrect message type">>,
+ ErrTxt = <<"User session not found">>,
Err = jlib:make_error_reply(
Packet,
?ERRT_SERVICE_UNAVAILABLE(Lang, ErrTxt)),
@@ -729,13 +730,10 @@ force_update_presence({LUser, LServer}) ->
-spec get_sm_backend(binary()) -> module().
get_sm_backend(Host) ->
- DBType = ejabberd_config:get_option({sm_db_type, Host},
- fun(mnesia) -> mnesia;
- (internal) -> mnesia;
- (odbc) -> sql;
- (sql) -> sql;
- (redis) -> redis
- end, mnesia),
+ DBType = ejabberd_config:get_option(
+ {sm_db_type, Host},
+ fun(T) -> ejabberd_config:v_db(?MODULE, T) end,
+ mnesia),
list_to_atom("ejabberd_sm_" ++ atom_to_list(DBType)).
-spec get_sm_backends() -> [module()].
@@ -808,11 +806,5 @@ kick_user(User, Server) ->
make_sid() ->
{p1_time_compat:unique_timestamp(), self()}.
-opt_type(sm_db_type) ->
- fun (mnesia) -> mnesia;
- (internal) -> mnesia;
- (sql) -> sql;
- (odbc) -> sql;
- (redis) -> redis
- end;
+opt_type(sm_db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
opt_type(_) -> [sm_db_type].
diff --git a/src/ejd2sql.erl b/src/ejd2sql.erl
index aa74286e..0457f6be 100644
--- a/src/ejd2sql.erl
+++ b/src/ejd2sql.erl
@@ -104,7 +104,7 @@ import_file(Server, FileName) ->
LServer = jid:nameprep(Server),
Mods = [{Mod, gen_mod:db_type(LServer, Mod)}
|| Mod <- modules(), gen_mod:is_loaded(LServer, Mod)],
- AuthMods = case lists:member(ejabberd_auth_internal,
+ AuthMods = case lists:member(ejabberd_auth_mnesia,
ejabberd_auth:auth_modules(LServer)) of
true ->
[{ejabberd_auth, mnesia}];
diff --git a/src/gen_mod.erl b/src/gen_mod.erl
index 26e662dc..f9639719 100644
--- a/src/gen_mod.erl
+++ b/src/gen_mod.erl
@@ -31,12 +31,12 @@
-export([start/0, start_module/2, start_module/3,
stop_module/2, stop_module_keep_config/2, get_opt/3,
- get_opt/4, get_opt_host/3, db_type/1, db_type/2,
+ get_opt/4, get_opt_host/3, db_type/2, db_type/3,
get_module_opt/4, get_module_opt/5, get_module_opt_host/3,
loaded_modules/1, loaded_modules_with_opts/1,
get_hosts/2, get_module_proc/2, is_loaded/2,
start_modules/0, start_modules/1, stop_modules/0, stop_modules/1,
- default_db/1, v_db/1, opt_type/1, db_mod/2, db_mod/3]).
+ opt_type/1, db_mod/2, db_mod/3]).
%%-export([behaviour_info/1]).
@@ -52,6 +52,7 @@
-callback start(binary(), opts()) -> any().
-callback stop(binary()) -> any().
+-callback mod_opt_type(atom()) -> fun((term()) -> term()) | [atom()].
-export_type([opts/0]).
-export_type([db_type/0]).
@@ -295,44 +296,46 @@ validate_opts(Module, Opts) ->
false
end, Opts).
--spec v_db(db_type() | internal) -> db_type().
-
-v_db(odbc) -> sql;
-v_db(sql) -> sql;
-v_db(internal) -> mnesia;
-v_db(mnesia) -> mnesia;
-v_db(riak) -> riak.
-
--spec db_type(opts()) -> db_type().
-
-db_type(Opts) ->
- db_type(global, Opts).
-
--spec db_type(binary() | global, atom() | opts()) -> db_type().
+-spec db_type(binary() | global, module()) -> db_type();
+ (opts(), module()) -> db_type().
+db_type(Opts, Module) when is_list(Opts) ->
+ db_type(global, Opts, Module);
db_type(Host, Module) when is_atom(Module) ->
- get_module_opt(Host, Module, db_type, fun v_db/1, default_db(Host));
-db_type(Host, Opts) when is_list(Opts) ->
- get_opt(db_type, Opts, fun v_db/1, default_db(Host)).
-
--spec default_db(binary() | global) -> db_type().
+ case catch Module:mod_opt_type(db_type) of
+ F when is_function(F) ->
+ case get_module_opt(Host, Module, db_type, F) of
+ undefined -> ejabberd_config:default_db(Host, Module);
+ Type -> Type
+ end;
+ _ ->
+ undefined
+ end.
-default_db(Host) ->
- ejabberd_config:get_option({default_db, Host}, fun v_db/1, mnesia).
+-spec db_type(binary(), opts(), module()) -> db_type().
+
+db_type(Host, Opts, Module) ->
+ case catch Module:mod_opt_type(db_type) of
+ F when is_function(F) ->
+ case get_opt(db_type, Opts, F) of
+ undefined -> ejabberd_config:default_db(Host, Module);
+ Type -> Type
+ end;
+ _ ->
+ undefined
+ end.
-spec db_mod(binary() | global | db_type(), module()) -> module().
-db_mod(odbc, Module) -> list_to_atom(atom_to_list(Module) ++ "_sql");
-db_mod(sql, Module) -> list_to_atom(atom_to_list(Module) ++ "_sql");
-db_mod(mnesia, Module) -> list_to_atom(atom_to_list(Module) ++ "_mnesia");
-db_mod(riak, Module) -> list_to_atom(atom_to_list(Module) ++ "_riak");
+db_mod(Type, Module) when is_atom(Type) ->
+ list_to_atom(atom_to_list(Module) ++ "_" ++ atom_to_list(Type));
db_mod(Host, Module) when is_binary(Host) orelse Host == global ->
db_mod(db_type(Host, Module), Module).
-spec db_mod(binary() | global, opts(), module()) -> module().
db_mod(Host, Opts, Module) when is_list(Opts) ->
- db_mod(db_type(Host, Opts), Module).
+ db_mod(db_type(Host, Opts, Module), Module).
-spec loaded_modules(binary()) -> [atom()].
@@ -380,6 +383,6 @@ get_module_proc(Host, Base) ->
is_loaded(Host, Module) ->
ets:member(ejabberd_modules, {Module, Host}).
-opt_type(default_db) -> fun v_db/1;
+opt_type(default_db) -> fun(T) when is_atom(T) -> T end;
opt_type(modules) -> fun (L) when is_list(L) -> L end;
opt_type(_) -> [default_db, modules].
diff --git a/src/mod_announce.erl b/src/mod_announce.erl
index d7251c50..9a9e665f 100644
--- a/src/mod_announce.erl
+++ b/src/mod_announce.erl
@@ -921,5 +921,5 @@ import(LServer, DBType, LA) ->
mod_opt_type(access) ->
fun (A) when is_atom(A) -> A end;
-mod_opt_type(db_type) -> fun gen_mod:v_db/1;
+mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
mod_opt_type(_) -> [access, db_type].
diff --git a/src/mod_caps.erl b/src/mod_caps.erl
index 3d5c360a..966a9baa 100644
--- a/src/mod_caps.erl
+++ b/src/mod_caps.erl
@@ -651,6 +651,6 @@ mod_opt_type(cache_life_time) ->
fun (I) when is_integer(I), I > 0 -> I end;
mod_opt_type(cache_size) ->
fun (I) when is_integer(I), I > 0 -> I end;
-mod_opt_type(db_type) -> fun gen_mod:v_db/1;
+mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
mod_opt_type(_) ->
[cache_life_time, cache_size, db_type].
diff --git a/src/mod_carboncopy.erl b/src/mod_carboncopy.erl
index ebf1d0b0..bb20bd2f 100644
--- a/src/mod_carboncopy.erl
+++ b/src/mod_carboncopy.erl
@@ -279,8 +279,5 @@ list(User, Server) ->
Mod:list(User, Server).
mod_opt_type(iqdisc) -> fun gen_iq_handler:check_type/1;
-mod_opt_type(db_type) ->
- fun(internal) -> mnesia;
- (mnesia) -> mnesia
- end;
+mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
mod_opt_type(_) -> [db_type, iqdisc].
diff --git a/src/mod_irc.erl b/src/mod_irc.erl
index e0c658de..f6487a1a 100644
--- a/src/mod_irc.erl
+++ b/src/mod_irc.erl
@@ -1253,7 +1253,7 @@ import(LServer, DBType, Data) ->
mod_opt_type(access) ->
fun (A) when is_atom(A) -> A end;
-mod_opt_type(db_type) -> fun gen_mod:v_db/1;
+mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
mod_opt_type(default_encoding) ->
fun iolist_to_binary/1;
mod_opt_type(host) -> fun iolist_to_binary/1;
diff --git a/src/mod_last.erl b/src/mod_last.erl
index 1af1847b..c39681f6 100644
--- a/src/mod_last.erl
+++ b/src/mod_last.erl
@@ -244,7 +244,7 @@ transform_options({node_start, {_, _, _} = Now}, Opts) ->
transform_options(Opt, Opts) ->
[Opt|Opts].
-mod_opt_type(db_type) -> fun gen_mod:v_db/1;
+mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
mod_opt_type(iqdisc) -> fun gen_iq_handler:check_type/1;
mod_opt_type(_) -> [db_type, iqdisc].
diff --git a/src/mod_mam.erl b/src/mod_mam.erl
index f84519a0..317fddfc 100644
--- a/src/mod_mam.erl
+++ b/src/mod_mam.erl
@@ -812,9 +812,9 @@ select(_LServer, JidRequestor, JidArchive, Start, End, _With, RSM,
_ ->
{Msgs, true, L}
end;
-select(LServer, From, From, Start, End, With, RSM, MsgType) ->
+select(LServer, From, To, Start, End, With, RSM, MsgType) ->
Mod = gen_mod:db_mod(LServer, ?MODULE),
- Mod:select(LServer, From, From, Start, End, With, RSM, MsgType).
+ Mod:select(LServer, From, To, Start, End, With, RSM, MsgType).
msg_to_el(#archive_msg{timestamp = TS, packet = Pkt1, nick = Nick, peer = Peer},
MsgType, JidRequestor, #jid{lserver = LServer} = JidArchive) ->
@@ -1017,12 +1017,7 @@ mod_opt_type(cache_life_time) ->
fun (I) when is_integer(I), I > 0 -> I end;
mod_opt_type(cache_size) ->
fun (I) when is_integer(I), I > 0 -> I end;
-mod_opt_type(db_type) ->
- fun(sql) -> sql;
- (odbc) -> sql;
- (internal) -> mnesia;
- (mnesia) -> mnesia
- end;
+mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
mod_opt_type(default) ->
fun (always) -> always;
(never) -> never;
diff --git a/src/mod_metrics.erl b/src/mod_metrics.erl
index c175fcb8..40484e48 100644
--- a/src/mod_metrics.erl
+++ b/src/mod_metrics.erl
@@ -39,7 +39,7 @@
s2s_send_packet, s2s_receive_packet,
remove_user, register_user]).
--export([start/2, stop/1, send_metrics/4, opt_type/1]).
+-export([start/2, stop/1, send_metrics/4, opt_type/1, mod_opt_type/1]).
-export([offline_message_hook/3,
sm_register_connection_hook/3, sm_remove_connection_hook/3,
@@ -126,3 +126,6 @@ send_metrics(Host, Probe, Peer, Port) ->
opt_type(_) ->
[].
+
+mod_opt_type(_) ->
+ [].
diff --git a/src/mod_muc.erl b/src/mod_muc.erl
index 6aa18631..3d098e0d 100644
--- a/src/mod_muc.erl
+++ b/src/mod_muc.erl
@@ -932,7 +932,7 @@ mod_opt_type(access_create) ->
fun (A) when is_atom(A) -> A end;
mod_opt_type(access_persistent) ->
fun (A) when is_atom(A) -> A end;
-mod_opt_type(db_type) -> fun gen_mod:v_db/1;
+mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
mod_opt_type(default_room_options) ->
fun (L) when is_list(L) -> L end;
mod_opt_type(history_size) ->
diff --git a/src/mod_offline.erl b/src/mod_offline.erl
index 356d89a6..4d8aba76 100644
--- a/src/mod_offline.erl
+++ b/src/mod_offline.erl
@@ -867,7 +867,7 @@ import(LServer, DBType, Data) ->
mod_opt_type(access_max_user_messages) ->
fun (A) -> A end;
-mod_opt_type(db_type) -> fun gen_mod:v_db/1;
+mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
mod_opt_type(store_empty_body) ->
fun (V) when is_boolean(V) -> V;
(unless_chat_state) -> unless_chat_state
diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl
index 413dcb52..ad13c27c 100644
--- a/src/mod_privacy.erl
+++ b/src/mod_privacy.erl
@@ -593,6 +593,6 @@ import(LServer, DBType, Data) ->
Mod = gen_mod:db_mod(DBType, ?MODULE),
Mod:import(LServer, Data).
-mod_opt_type(db_type) -> fun gen_mod:v_db/1;
+mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
mod_opt_type(iqdisc) -> fun gen_iq_handler:check_type/1;
mod_opt_type(_) -> [db_type, iqdisc].
diff --git a/src/mod_private.erl b/src/mod_private.erl
index 029789e6..38e42ca4 100644
--- a/src/mod_private.erl
+++ b/src/mod_private.erl
@@ -173,6 +173,6 @@ import(LServer, DBType, PD) ->
Mod = gen_mod:db_mod(DBType, ?MODULE),
Mod:import(LServer, PD).
-mod_opt_type(db_type) -> fun gen_mod:v_db/1;
+mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
mod_opt_type(iqdisc) -> fun gen_iq_handler:check_type/1;
mod_opt_type(_) -> [db_type, iqdisc].
diff --git a/src/mod_pubsub.erl b/src/mod_pubsub.erl
index e42d5c05..35173a4f 100644
--- a/src/mod_pubsub.erl
+++ b/src/mod_pubsub.erl
@@ -254,10 +254,12 @@ init([ServerHost, Opts]) ->
fun(A) when is_integer(A) andalso A >= 0 -> A end, ?MAXITEMS),
MaxSubsNode = gen_mod:get_opt(max_subscriptions_node, Opts,
fun(A) when is_integer(A) andalso A >= 0 -> A end, undefined),
- DefaultNodeCfg = gen_mod:get_opt(default_node_config, Opts,
- fun(A) when is_list(A) -> filter_node_options(A) end, []),
pubsub_index:init(Host, ServerHost, Opts),
{Plugins, NodeTree, PepMapping} = init_plugins(Host, ServerHost, Opts),
+ DefaultModule = plugin(Host, hd(Plugins)),
+ BaseOptions = DefaultModule:options(),
+ DefaultNodeCfg = gen_mod:get_opt(default_node_config, Opts,
+ fun(A) when is_list(A) -> filter_node_options(A, BaseOptions) end, []),
mnesia:create_table(pubsub_last_item,
[{ram_copies, [node()]},
{attributes, record_info(fields, pubsub_last_item)}]),
@@ -2101,6 +2103,9 @@ subscribe_node(Host, Node, From, JID, Configuration) ->
Type = TNode#pubsub_node.type,
Options = TNode#pubsub_node.options,
send_items(Host, Node, Nidx, Type, Options, Subscriber, last),
+ ServerHost = serverhost(Host),
+ ejabberd_hooks:run(pubsub_subscribe_node, ServerHost,
+ [ServerHost, Host, Node, Subscriber, SubId]),
case Result of
default -> {result, Reply({subscribed, SubId})};
_ -> {result, Result}
@@ -2147,7 +2152,11 @@ unsubscribe_node(Host, Node, From, Subscriber, SubId) ->
node_call(Host, Type, unsubscribe_node, [Nidx, From, Subscriber, SubId])
end,
case transaction(Host, Node, Action, sync_dirty) of
- {result, {_, default}} -> {result, []};
+ {result, {_, default}} ->
+ ServerHost = serverhost(Host),
+ ejabberd_hooks:run(pubsub_unsubscribe_node, ServerHost,
+ [ServerHost, Host, Node, Subscriber, SubId]),
+ {result, []};
% {result, {_, Result}} -> {result, Result};
Error -> Error
end.
@@ -3163,11 +3172,9 @@ subscription_to_string(_) -> <<"none">>.
Host :: mod_pubsub:host())
-> jid()
).
-service_jid(Host) ->
- case Host of
- {U, S, _} -> {jid, U, S, <<>>, U, S, <<>>};
- _ -> {jid, <<>>, Host, <<>>, <<>>, Host, <<>>}
- end.
+service_jid(#jid{} = Jid) -> Jid;
+service_jid({U, S, R}) -> jid:make(U, S, R);
+service_jid(Host) -> jid:make(<<>>, Host, <<>>).
%% @spec (LJID, NotifyType, Depth, NodeOptions, SubOptions) -> boolean()
%% LJID = jid()
@@ -3516,7 +3523,7 @@ broadcast_stanza(Host, _Node, _Nidx, _Type, NodeOptions, SubsByDepth, NotifyType
end, SubIDsByJID).
broadcast_stanza({LUser, LServer, LResource}, Publisher, Node, Nidx, Type, NodeOptions, SubsByDepth, NotifyType, BaseStanza, SHIM) ->
- broadcast_stanza({LUser, LServer, LResource}, Node, Nidx, Type, NodeOptions, SubsByDepth, NotifyType, BaseStanza, SHIM),
+ broadcast_stanza({LUser, LServer, <<>>}, Node, Nidx, Type, NodeOptions, SubsByDepth, NotifyType, BaseStanza, SHIM),
%% Handles implicit presence subscriptions
SenderResource = user_resource(LUser, LServer, LResource),
case ejabberd_sm:get_session_pid(LUser, LServer, SenderResource) of
@@ -3680,11 +3687,11 @@ node_plugin_options(Host, Type) ->
Result ->
Result
end.
-filter_node_options(Options) ->
+filter_node_options(Options, BaseOptions) ->
lists:foldl(fun({Key, Val}, Acc) ->
DefaultValue = proplists:get_value(Key, Options, Val),
[{Key, DefaultValue}|Acc]
- end, [], node_flat:options()).
+ end, [], BaseOptions).
node_owners_action(Host, Type, Nidx, []) ->
case gen_mod:db_type(serverhost(Host), ?MODULE) of
@@ -4468,7 +4475,7 @@ purge_offline(Host, LJID, Node) ->
mod_opt_type(access_createnode) ->
fun (A) when is_atom(A) -> A end;
-mod_opt_type(db_type) -> fun gen_mod:v_db/1;
+mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
mod_opt_type(host) -> fun iolist_to_binary/1;
mod_opt_type(ignore_pep_from_offline) ->
fun (A) when is_boolean(A) -> A end;
diff --git a/src/mod_roster.erl b/src/mod_roster.erl
index 16354dd8..b3a627f7 100644
--- a/src/mod_roster.erl
+++ b/src/mod_roster.erl
@@ -1236,7 +1236,7 @@ import(LServer, DBType, R) ->
mod_opt_type(access) ->
fun (A) when is_atom(A) -> A end;
-mod_opt_type(db_type) -> fun gen_mod:v_db/1;
+mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
mod_opt_type(iqdisc) -> fun gen_iq_handler:check_type/1;
mod_opt_type(managers) ->
fun (B) when is_list(B) -> B end;
diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl
index 6670cf77..76a619c9 100644
--- a/src/mod_shared_roster.erl
+++ b/src/mod_shared_roster.erl
@@ -1120,5 +1120,5 @@ import(LServer, DBType, Data) ->
Mod = gen_mod:db_mod(DBType, ?MODULE),
Mod:import(LServer, Data).
-mod_opt_type(db_type) -> fun gen_mod:v_db/1;
+mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
mod_opt_type(_) -> [db_type].
diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl
index e5f5d9e3..5e042528 100644
--- a/src/mod_vcard.erl
+++ b/src/mod_vcard.erl
@@ -596,7 +596,7 @@ import(LServer, DBType, VCard) ->
mod_opt_type(allow_return_all) ->
fun (B) when is_boolean(B) -> B end;
-mod_opt_type(db_type) -> fun gen_mod:v_db/1;
+mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
mod_opt_type(host) -> fun iolist_to_binary/1;
mod_opt_type(iqdisc) -> fun gen_iq_handler:check_type/1;
mod_opt_type(matches) ->
diff --git a/src/mod_vcard_xupdate.erl b/src/mod_vcard_xupdate.erl
index 198312c3..041b0b64 100644
--- a/src/mod_vcard_xupdate.erl
+++ b/src/mod_vcard_xupdate.erl
@@ -133,5 +133,5 @@ import(LServer, DBType, LA) ->
Mod = gen_mod:db_mod(DBType, ?MODULE),
Mod:import(LServer, LA).
-mod_opt_type(db_type) -> fun gen_mod:v_db/1;
+mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
mod_opt_type(_) -> [db_type].
diff --git a/src/mod_vcard_xupdate_riak.erl b/src/mod_vcard_xupdate_riak.erl
index 129a0c6a..242485bf 100644
--- a/src/mod_vcard_xupdate_riak.erl
+++ b/src/mod_vcard_xupdate_riak.erl
@@ -8,6 +8,8 @@
%%%-------------------------------------------------------------------
-module(mod_vcard_xupdate_riak).
+-behaviour(mod_vcard_xupdate).
+
%% API
-export([init/2, import/2, add_xupdate/3, get_xupdate/2, remove_xupdate/2]).
diff --git a/src/mod_vcard_xupdate_sql.erl b/src/mod_vcard_xupdate_sql.erl
index 7f0079dd..00bb2950 100644
--- a/src/mod_vcard_xupdate_sql.erl
+++ b/src/mod_vcard_xupdate_sql.erl
@@ -8,6 +8,8 @@
%%%-------------------------------------------------------------------
-module(mod_vcard_xupdate_sql).
+-behaviour(mod_vcard_xupdate).
+
%% API
-export([init/2, import/2, add_xupdate/3, get_xupdate/2, remove_xupdate/2,
import/1, export/1]).
diff --git a/src/shaper.erl b/src/shaper.erl
index a136c213..eb82b8fa 100644
--- a/src/shaper.erl
+++ b/src/shaper.erl
@@ -124,9 +124,13 @@ update(#maxrate{} = State, Size) ->
true -> 0
end,
NextNow = p1_time_compat:system_time(micro_seconds) + Pause * 1000,
+ Div = case NextNow - State#maxrate.lasttime of
+ 0 -> 1;
+ V -> V
+ end,
{State#maxrate{lastrate =
(State#maxrate.lastrate +
- 1000000 * Size / (NextNow - State#maxrate.lasttime))
+ 1000000 * Size / Div)
/ 2,
lasttime = NextNow},
Pause}.
diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl
index e2f26807..3edbf587 100644
--- a/test/ejabberd_SUITE.erl
+++ b/test/ejabberd_SUITE.erl
@@ -303,6 +303,8 @@ db_tests(DB) when DB == mnesia; DB == redis ->
[client_state_master, client_state_slave]},
{test_muc, [parallel],
[muc_master, muc_slave]},
+ {test_muc_mam, [parallel],
+ [muc_mam_master, muc_mam_slave]},
{test_announce, [sequence],
[announce_master, announce_slave]},
{test_vcard_xupdate, [parallel],
@@ -343,6 +345,8 @@ db_tests(_) ->
[mam_new_master, mam_new_slave]},
{test_muc, [parallel],
[muc_master, muc_slave]},
+ {test_muc_mam, [parallel],
+ [muc_mam_master, muc_mam_slave]},
{test_announce, [sequence],
[announce_master, announce_slave]},
{test_vcard_xupdate, [parallel],
@@ -1189,6 +1193,92 @@ proxy65_slave(Config) ->
socks5_recv(Socks5, Data),
disconnect(Config).
+send_messages_to_room(Config, Range) ->
+ MyNick = ?config(master_nick, Config),
+ Room = muc_room_jid(Config),
+ MyNickJID = jid:replace_resource(Room, MyNick),
+ lists:foreach(
+ fun(N) ->
+ Text = #text{data = integer_to_binary(N)},
+ I = send(Config, #message{to = Room, body = [Text],
+ type = groupchat}),
+ ?recv1(#message{from = MyNickJID, id = I,
+ type = groupchat,
+ body = [Text]})
+ end, Range).
+
+retrieve_messages_from_room_via_mam(Config, Range) ->
+ MyNick = ?config(master_nick, Config),
+ Room = muc_room_jid(Config),
+ MyNickJID = jid:replace_resource(Room, MyNick),
+ QID = randoms:get_string(),
+ I = send(Config, #iq{type = set, to = Room,
+ sub_els = [#mam_query{xmlns = ?NS_MAM_1, id = QID}]}),
+ lists:foreach(
+ fun(N) ->
+ Text = #text{data = integer_to_binary(N)},
+ ?recv1(#message{
+ to = MyJID, from = Room,
+ sub_els =
+ [#mam_result{
+ xmlns = ?NS_MAM_1,
+ queryid = QID,
+ sub_els =
+ [#forwarded{
+ delay = #delay{},
+ sub_els = [#message{
+ from = MyNickJID,
+ type = groupchat,
+ body = [Text]}]}]}]})
+ end, Range),
+ ?recv1(#iq{from = Room, id = I, type = result, sub_els = []}).
+
+muc_mam_master(Config) ->
+ MyJID = my_jid(Config),
+ MyNick = ?config(master_nick, Config),
+ Room = muc_room_jid(Config),
+ MyNickJID = jid:replace_resource(Room, MyNick),
+ %% Joining
+ send(Config, #presence{to = MyNickJID, sub_els = [#muc{}]}),
+ %% Receive self-presence
+ ?recv1(#presence{from = MyNickJID}),
+ %% MAM feature should not be advertised at this point,
+ %% because MAM is not enabled so far
+ false = is_feature_advertised(Config, ?NS_MAM_1, Room),
+ %% Fill in some history
+ send_messages_to_room(Config, lists:seq(1, 21)),
+ %% We now should be able to retrieve those via MAM, even though
+ %% MAM is disabled. However, only last 20 messages should be received.
+ retrieve_messages_from_room_via_mam(Config, lists:seq(2, 21)),
+ %% Now enable MAM for the conference
+ %% Retrieve config first
+ #iq{type = result, sub_els = [#muc_owner{config = #xdata{} = RoomCfg}]} =
+ send_recv(Config, #iq{type = get, sub_els = [#muc_owner{}],
+ to = Room}),
+ %% Find the MAM field in the config and enable it
+ NewFields = lists:flatmap(
+ fun(#xdata_field{var = <<"muc#roomconfig_mam">> = Var}) ->
+ [#xdata_field{var = Var, values = [<<"1">>]}];
+ (_) ->
+ []
+ end, RoomCfg#xdata.fields),
+ NewRoomCfg = #xdata{type = submit, fields = NewFields},
+ I1 = send(Config, #iq{type = set, to = Room,
+ sub_els = [#muc_owner{config = NewRoomCfg}]}),
+ ?recv2(#iq{type = result, id = I1},
+ #message{from = Room, type = groupchat,
+ sub_els = [#muc_user{status_codes = [104]}]}),
+ %% Check if MAM has been enabled
+ true = is_feature_advertised(Config, ?NS_MAM_1, Room),
+ %% We now sending some messages again
+ send_messages_to_room(Config, lists:seq(1, 5)),
+ %% And retrieve them via MAM again.
+ retrieve_messages_from_room_via_mam(Config, lists:seq(1, 5)),
+ disconnect(Config).
+
+muc_mam_slave(Config) ->
+ disconnect(Config).
+
muc_master(Config) ->
MyJID = my_jid(Config),
PeerJID = ?config(slave, Config),
diff --git a/test/ejabberd_SUITE_data/ejabberd.yml b/test/ejabberd_SUITE_data/ejabberd.yml
index bd7f958d..869c24c7 100644
--- a/test/ejabberd_SUITE_data/ejabberd.yml
+++ b/test/ejabberd_SUITE_data/ejabberd.yml
@@ -424,7 +424,7 @@ listen:
port: @@web_port@@
module: ejabberd_http
captcha: true
-loglevel: 4
+loglevel: @@loglevel@@
max_fsm_queue: 1000
modules:
mod_adhoc: []
diff --git a/test/suite.erl b/test/suite.erl
index 8000e1d2..f37b51ea 100644
--- a/test/suite.erl
+++ b/test/suite.erl
@@ -31,6 +31,7 @@ init_config(Config) ->
{ok, CfgContentTpl} = file:read_file(ConfigPathTpl),
CfgContent = process_config_tpl(CfgContentTpl, [
{c2s_port, 5222},
+ {loglevel, 4},
{s2s_port, 5269},
{web_port, 5280},
{mysql_server, <<"localhost">>},
diff --git a/tools/xmpp_codec.erl b/tools/xmpp_codec.erl
index 01e0676a..52950fea 100644
--- a/tools/xmpp_codec.erl
+++ b/tools/xmpp_codec.erl
@@ -103,6 +103,8 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) ->
decode_mam_fin(<<"urn:xmpp:mam:0">>, IgnoreEls, _el);
{<<"prefs">>, <<"urn:xmpp:mam:0">>} ->
decode_mam_prefs(<<"urn:xmpp:mam:0">>, IgnoreEls, _el);
+ {<<"prefs">>, <<"urn:xmpp:mam:1">>} ->
+ decode_mam_prefs(<<"urn:xmpp:mam:1">>, IgnoreEls, _el);
{<<"prefs">>, <<"urn:xmpp:mam:tmp">>} ->
decode_mam_prefs(<<"urn:xmpp:mam:tmp">>, IgnoreEls,
_el);
@@ -116,6 +118,8 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) ->
decode_mam_jid(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el);
{<<"result">>, <<"urn:xmpp:mam:0">>} ->
decode_mam_result(<<"urn:xmpp:mam:0">>, IgnoreEls, _el);
+ {<<"result">>, <<"urn:xmpp:mam:1">>} ->
+ decode_mam_result(<<"urn:xmpp:mam:1">>, IgnoreEls, _el);
{<<"result">>, <<"urn:xmpp:mam:tmp">>} ->
decode_mam_result(<<"urn:xmpp:mam:tmp">>, IgnoreEls,
_el);
@@ -124,6 +128,8 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) ->
_el);
{<<"query">>, <<"urn:xmpp:mam:0">>} ->
decode_mam_query(<<"urn:xmpp:mam:0">>, IgnoreEls, _el);
+ {<<"query">>, <<"urn:xmpp:mam:1">>} ->
+ decode_mam_query(<<"urn:xmpp:mam:1">>, IgnoreEls, _el);
{<<"query">>, <<"urn:xmpp:mam:tmp">>} ->
decode_mam_query(<<"urn:xmpp:mam:tmp">>, IgnoreEls,
_el);
@@ -1141,14 +1147,17 @@ is_known_tag({xmlel, _name, _attrs, _} = _el) ->
{<<"forwarded">>, <<"urn:xmpp:forward:0">>} -> true;
{<<"fin">>, <<"urn:xmpp:mam:0">>} -> true;
{<<"prefs">>, <<"urn:xmpp:mam:0">>} -> true;
+ {<<"prefs">>, <<"urn:xmpp:mam:1">>} -> true;
{<<"prefs">>, <<"urn:xmpp:mam:tmp">>} -> true;
{<<"always">>, <<"urn:xmpp:mam:tmp">>} -> true;
{<<"never">>, <<"urn:xmpp:mam:tmp">>} -> true;
{<<"jid">>, <<"urn:xmpp:mam:tmp">>} -> true;
{<<"result">>, <<"urn:xmpp:mam:0">>} -> true;
+ {<<"result">>, <<"urn:xmpp:mam:1">>} -> true;
{<<"result">>, <<"urn:xmpp:mam:tmp">>} -> true;
{<<"archived">>, <<"urn:xmpp:mam:tmp">>} -> true;
{<<"query">>, <<"urn:xmpp:mam:0">>} -> true;
+ {<<"query">>, <<"urn:xmpp:mam:1">>} -> true;
{<<"query">>, <<"urn:xmpp:mam:tmp">>} -> true;
{<<"with">>, <<"urn:xmpp:mam:tmp">>} -> true;
{<<"end">>, <<"urn:xmpp:mam:tmp">>} -> true;
diff --git a/tools/xmpp_codec.spec b/tools/xmpp_codec.spec
index e61b951c..536a11df 100644
--- a/tools/xmpp_codec.spec
+++ b/tools/xmpp_codec.spec
@@ -2145,7 +2145,7 @@
-xml(mam_query,
#elem{name = <<"query">>,
- xmlns = [<<"urn:xmpp:mam:0">>, <<"urn:xmpp:mam:tmp">>],
+ xmlns = [<<"urn:xmpp:mam:0">>, <<"urn:xmpp:mam:1">>, <<"urn:xmpp:mam:tmp">>],
result = {mam_query, '$xmlns', '$id', '$start', '$end', '$with',
'$rsm', '$xdata'},
attrs = [#attr{name = <<"queryid">>, label = '$id'},
@@ -2168,7 +2168,7 @@
-xml(mam_result,
#elem{name = <<"result">>,
- xmlns = [<<"urn:xmpp:mam:0">>, <<"urn:xmpp:mam:tmp">>],
+ xmlns = [<<"urn:xmpp:mam:0">>, <<"urn:xmpp:mam:1">>, <<"urn:xmpp:mam:tmp">>],
result = {mam_result, '$xmlns', '$queryid', '$id', '$_els'},
attrs = [#attr{name = <<"queryid">>},
#attr{name = <<"xmlns">>},
@@ -2196,7 +2196,7 @@
-xml(mam_prefs,
#elem{name = <<"prefs">>,
- xmlns = [<<"urn:xmpp:mam:0">>, <<"urn:xmpp:mam:tmp">>],
+ xmlns = [<<"urn:xmpp:mam:0">>, <<"urn:xmpp:mam:1">>, <<"urn:xmpp:mam:tmp">>],
result = {mam_prefs, '$xmlns', '$default', '$always', '$never'},
attrs = [#attr{name = <<"default">>,
dec = {dec_enum, [[always, never, roster]]},
diff --git a/vars.config.in b/vars.config.in
index 44316f8a..57fade8d 100644
--- a/vars.config.in
+++ b/vars.config.in
@@ -40,6 +40,7 @@
{sysconfdir, "{{release_dir}}/etc"}.
{installuser, "@INSTALLUSER@"}.
{erl, "{{release_dir}}/{{erts_vsn}}/bin/erl"}.
+{epmd, "{{release_dir}}/{{erts_vsn}}/bin/epmd"}.
{localstatedir, "{{release_dir}}/var"}.
{libdir, "{{release_dir}}/lib"}.
{docdir, "{{release_dir}}/doc"}.