summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.in19
-rw-r--r--README2
-rw-r--r--configure.ac9
-rw-r--r--ejabberd.yml.example4
-rwxr-xr-xejabberdctl.template27
-rw-r--r--include/mod_muc_room.hrl2
-rw-r--r--rebar.config.script48
-rw-r--r--src/ejabberd_admin.erl2
-rw-r--r--src/ejabberd_app.erl1
-rw-r--r--src/ejabberd_c2s.erl13
-rw-r--r--src/ejabberd_http.erl122
-rw-r--r--src/ejabberd_listener.erl21
-rw-r--r--src/ejabberd_receiver.erl60
-rw-r--r--src/ejabberd_s2s_in.erl19
-rw-r--r--src/ejabberd_s2s_out.erl12
-rw-r--r--src/ejabberd_sup.erl8
-rw-r--r--src/jlib.erl80
-rw-r--r--src/mod_client_state.erl4
-rw-r--r--src/mod_http_upload.erl544
-rw-r--r--src/mod_http_upload_quota.erl186
-rw-r--r--src/mod_mam.erl2
-rw-r--r--src/mod_muc.erl15
-rw-r--r--src/mod_muc_room.erl136
-rw-r--r--src/mod_ping.erl4
-rw-r--r--src/mod_vcard.erl2
-rw-r--r--src/mod_vcard_ldap.erl4
-rw-r--r--vars.config.in1
27 files changed, 740 insertions, 607 deletions
diff --git a/Makefile.in b/Makefile.in
index 8dd6bf58..79ac69c4 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -112,12 +112,19 @@ spec:
$(ERL) -noinput +B -pa ebin -pa deps/*/ebin -eval \
'case xml_gen:compile("tools/xmpp_codec.spec") of ok -> halt(0); _ -> halt(1) end.'
-TO_DEST=$(foreach path,$(1),$(if $(filter deps/%,$(path)),$(patsubst deps/%,$(LIBDIR)/%,$(path)),$(patsubst %,$(LIBDIR)/ejabberd/%,$(path))))
+JOIN_PATHS=$(if $(wordlist 2,1000,$(1)),$(firstword $(1))/$(call JOIN_PATHS,$(wordlist 2,1000,$(1))),$(1))
+
+ELIXIR_TO_DEST=$(LIBDIR) $(wordlist 2,2,$(1)) $(wordlist 5,1000,$(1))
+DEPS_TO_DEST=$(LIBDIR) $(wordlist 2,1000,$(1))
+MAIN_TO_DEST=$(LIBDIR) ejabberd $(1)
+TO_DEST_SINGLE=$(if $(subst XdepsX,,X$(word 1,$(1))X),$(call MAIN_TO_DEST,$(1)),$(if $(subst XlibX,,X$(word 3,$(1))X),$(call DEPS_TO_DEST,$(1)),$(call ELIXIR_TO_DEST,$(1))))
+TO_DEST=$(foreach path,$(1),$(call JOIN_PATHS,$(call TO_DEST_SINGLE,$(subst /, ,$(path)))))
+
FILTER_DIRS=$(foreach path,$(1),$(if $(wildcard $(path)/*),,$(path)))
FILES_WILDCARD=$(call FILTER_DIRS,$(foreach w,$(1),$(wildcard $(w))))
-DEPS_FILES:=$(call FILES_WILDCARD,deps/*/ebin/*.beam deps/*/ebin/*.app deps/*/priv/* deps/*/priv/lib/* deps/*/priv/bin/* deps/*/include/*.hrl)
-DEPS_FILES_FILTERED:=$(filter-out %/epam,$(DEPS_FILES))
+DEPS_FILES:=$(call FILES_WILDCARD,deps/*/ebin/*.beam deps/*/ebin/*.app deps/*/priv/* deps/*/priv/lib/* deps/*/priv/bin/* deps/*/include/*.hrl deps/*/lib/*/ebin/*.beam deps/*/lib/*/ebin/*.app)
+DEPS_FILES_FILTERED:=$(filter-out %/epam deps/elixir/ebin/elixir.app,$(DEPS_FILES))
DEPS_DIRS:=$(sort deps/ $(wildcard deps/*) $(dir $(DEPS_FILES)))
MAIN_FILES:=$(filter-out %/configure.beam,$(call FILES_WILDCARD,ebin/*.beam ebin/*.app priv/msgs/*.msg priv/lib/* include/*.hrl))
@@ -129,7 +136,7 @@ endef
$(foreach file,$(DEPS_FILES_FILTERED) $(MAIN_FILES),$(eval $(call COPY_template,$(file))))
-$(call TO_DEST,$(MAIN_DIRS) $(DEPS_DIRS)):
+$(sort $(call TO_DEST,$(MAIN_DIRS) $(DEPS_DIRS))):
$(INSTALL) -d $@
$(call TO_DEST,deps/p1_pam/priv/bin/epam): $(LIBDIR)/%: deps/% $(call TO_DEST,deps/p1_pam/priv/bin/)
@@ -172,10 +179,6 @@ install: all copy-files
-e "s*@installuser@*$(INIT_USER)*" ejabberd.init.template \
> ejabberd.init
chmod 755 ejabberd.init
- # Install Elixir and Elixir dependancies
- -$(INSTALL) -m 644 deps/*/lib/*/ebin/*.app $(BEAMDIR)
- -$(INSTALL) -m 644 deps/*/lib/*/ebin/*.beam $(BEAMDIR)
- rm -f $(BEAMDIR)/configure.beam
#
# Binary C programs
$(INSTALL) -d $(PBINDIR)
diff --git a/README b/README
index f03c194a..f6e174ce 100644
--- a/README
+++ b/README
@@ -107,7 +107,7 @@ To compile ejabberd you need:
- Libexpat 1.95 or higher.
- Libyaml 0.1.4 or higher.
- Erlang/OTP 17.1 or higher.
- - OpenSSL 0.9.8 or higher, for STARTTLS, SASL and SSL encryption.
+ - OpenSSL 1.0.0 or higher, for STARTTLS, SASL and SSL encryption.
- Zlib 1.2.3 or higher, for Stream Compression support (XEP-0138). Optional.
- PAM library. Optional. For Pluggable Authentication Modules (PAM).
- GNU Iconv 1.8 or higher, for the IRC Transport (mod_irc). Optional. Not
diff --git a/configure.ac b/configure.ac
index c7e7bcd4..57b9aa74 100644
--- a/configure.ac
+++ b/configure.ac
@@ -83,14 +83,6 @@ AC_ARG_ENABLE(roster_gateway_workaround,
*) AC_MSG_ERROR(bad value ${enableval} for --enable-roster-gateway-workaround) ;;
esac],[roster_gateway_workaround=false])
-AC_ARG_ENABLE(transient_supervisors,
-[AC_HELP_STRING([--disable-transient-supervisors], [disable Erlang supervision for transient processes (default: no)])],
-[case "${enableval}" in
- yes) transient_supervisors=true ;;
- no) transient_supervisors=false ;;
- *) AC_MSG_ERROR(bad value ${enableval} for --enable-transient_supervisors) ;;
-esac],[transient_supervisors=true])
-
AC_ARG_ENABLE(full_xml,
[AC_HELP_STRING([--enable-full-xml], [use XML features in XMPP stream (ex: CDATA) (default: no, requires XML compliant clients)])],
[case "${enableval}" in
@@ -256,7 +248,6 @@ fi
AC_SUBST(hipe)
AC_SUBST(roster_gateway_workaround)
-AC_SUBST(transient_supervisors)
AC_SUBST(full_xml)
AC_SUBST(nif)
AC_SUBST(db_type)
diff --git a/ejabberd.yml.example b/ejabberd.yml.example
index b4278eed..e20dc0df 100644
--- a/ejabberd.yml.example
+++ b/ejabberd.yml.example
@@ -167,6 +167,7 @@ listen:
## -
## port: 4560
## module: ejabberd_xmlrpc
+ ## access_commands: {}
-
port: 5280
module: ejabberd_http
@@ -658,7 +659,8 @@ modules:
mod_shared_roster: {}
mod_stats: {}
mod_time: {}
- mod_vcard: {}
+ mod_vcard:
+ search: false
mod_version: {}
##
diff --git a/ejabberdctl.template b/ejabberdctl.template
index c7d76eff..bd791ced 100755
--- a/ejabberdctl.template
+++ b/ejabberdctl.template
@@ -228,6 +228,21 @@ iexlive()
--erl \"$ERLANG_OPTS\" --erl $ARGS --erl \"$@\""
}
+# start server in the foreground
+foreground()
+{
+ check_start
+ $EXEC_CMD "$ERL \
+ $NAME $ERLANG_NODE \
+ -noinput \
+ -pa $EJABBERD_EBIN_PATH \
+ $MNESIA_OPTS \
+ $KERNEL_OPTS \
+ $EJABBERD_OPTS \
+ -s ejabberd \
+ $ERLANG_OPTS $ARGS \"$@\""
+}
+
debugwarning()
{
if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then
@@ -300,11 +315,12 @@ help()
{
echo ""
echo "Commands to start an ejabberd node:"
- echo " start Start an ejabberd node in server mode"
- echo " debug Attach an interactive Erlang shell to a running ejabberd node"
- echo " iexdebug Attach an interactive Elixir shell to a running ejabberd node"
- echo " live Start an ejabberd node in live (interactive) mode"
- echo " iexlive Start an ejabberd node in live (interactive) mode, within an Elixir shell"
+ echo " start Start an ejabberd node in server mode"
+ echo " debug Attach an interactive Erlang shell to a running ejabberd node"
+ echo " iexdebug Attach an interactive Elixir shell to a running ejabberd node"
+ echo " live Start an ejabberd node in live (interactive) mode"
+ echo " iexlive Start an ejabberd node in live (interactive) mode, within an Elixir shell"
+ echo " foreground Start an ejabberd node in server mode (attached)"
echo ""
echo "Optional parameters when starting an ejabberd node:"
echo " --config-dir dir Config ejabberd: $ETC_DIR"
@@ -458,6 +474,7 @@ case $ARGS in
' iexdebug') iexdebug;;
' live') live;;
' iexlive') iexlive;;
+ ' foreground') foreground;;
' ping'*) ping ${ARGS# ping};;
' etop') etop;;
' started') wait_for_status 0 30 2;; # wait 30x2s before timeout
diff --git a/include/mod_muc_room.hrl b/include/mod_muc_room.hrl
index c90a5c02..51e575db 100644
--- a/include/mod_muc_room.hrl
+++ b/include/mod_muc_room.hrl
@@ -56,6 +56,8 @@
password_protected = false :: boolean(),
password = <<"">> :: binary(),
anonymous = true :: boolean(),
+ presence_broadcast = [moderator, participant, visitor] ::
+ [moderator | participant | visitor],
allow_voice_requests = true :: boolean(),
voice_request_min_interval = 1800 :: non_neg_integer(),
max_users = ?MAX_USERS_DEFAULT :: non_neg_integer() | none,
diff --git a/rebar.config.script b/rebar.config.script
index 833595d4..cdd2a65c 100644
--- a/rebar.config.script
+++ b/rebar.config.script
@@ -19,8 +19,6 @@ Cfg = case file:consult("vars.config") of
Macros = lists:flatmap(
fun({roster_gateway_workaround, true}) ->
[{d, 'ROSTER_GATEWAY_WORKAROUND'}];
- ({transient_supervisors, false}) ->
- [{d, 'NO_TRANSIENT_SUPERVISORS'}];
({nif, true}) ->
[{d, 'NIF'}];
({db_type, mssql}) ->
@@ -54,17 +52,17 @@ SrcDirs = lists:foldl(
Acc
end, [], Cfg),
-Deps = [{p1_cache_tab, ".*", {git, "https://github.com/processone/cache_tab", "f7ea12b0ba962a3d2f9a406d2954cf7de4e27230"}},
- {p1_tls, ".*", {git, "https://github.com/processone/tls", "e56321afd974e9da33da913cd31beebc8e73e75f"}},
- {p1_stringprep, ".*", {git, "https://github.com/processone/stringprep", "3c640237a3a7831dc39de6a6d329d3a9af25c579"}},
- {p1_xml, ".*", {git, "https://github.com/processone/xml", "1c8b016b0ac7986efb823baf1682a43565449e65"}},
- {esip, ".*", {git, "https://github.com/processone/p1_sip", "d662d3fe7f6288b444ea321d854de0bd6d40e022"}},
- {p1_stun, ".*", {git, "https://github.com/processone/stun", "061bdae484268cbf0457ad4797e74b8516df3ad1"}},
- {p1_yaml, ".*", {git, "https://github.com/processone/p1_yaml", "79f756ba73a235c4d3836ec07b5f7f2b55f49638"}},
- {p1_utils, ".*", {git, "https://github.com/processone/p1_utils", "d7800881e6702723ce58b7646b60c9e4cd25d563"}},
- {jiffy, ".*", {git, "https://github.com/davisp/jiffy", "cfc61a2e952dc3182e0f9b1473467563699992e2"}},
- {oauth2, ".*", {git, "https://github.com/prefiks/oauth2.git", "e6da9912e5d8f658e7e868f41a102d085bdbef59"}},
- {xmlrpc, ".*", {git, "https://github.com/rds13/xmlrpc.git", "42e6e96a0fe7106830274feed915125feb1056f3"}}],
+Deps = [{p1_cache_tab, ".*", {git, "https://github.com/processone/cache_tab"}},
+ {p1_tls, ".*", {git, "https://github.com/processone/tls"}},
+ {p1_stringprep, ".*", {git, "https://github.com/processone/stringprep"}},
+ {p1_xml, ".*", {git, "https://github.com/processone/xml"}},
+ {esip, ".*", {git, "https://github.com/processone/p1_sip"}},
+ {p1_stun, ".*", {git, "https://github.com/processone/stun"}},
+ {p1_yaml, ".*", {git, "https://github.com/processone/p1_yaml"}},
+ {p1_utils, ".*", {git, "https://github.com/processone/p1_utils"}},
+ {jiffy, ".*", {git, "https://github.com/davisp/jiffy"}},
+ {oauth2, ".*", {git, "https://github.com/prefiks/oauth2.git"}},
+ {xmlrpc, ".*", {git, "https://github.com/rds13/xmlrpc.git"}}],
CFLags = proplists:get_value(cflags, Cfg, ""),
CPPFLags = proplists:get_value(cppflags, Cfg, ""),
@@ -94,30 +92,30 @@ PostHooks = [ConfigureCmd("p1_tls", ""),
CfgDeps = lists:flatmap(
fun({mysql, true}) ->
- [{p1_mysql, ".*", {git, "https://github.com/processone/mysql", "dfa87da95f8fdb92e270741c2a53f796b682f918"}}];
+ [{p1_mysql, ".*", {git, "https://github.com/processone/mysql"}}];
({pgsql, true}) ->
- [{p1_pgsql, ".*", {git, "https://github.com/processone/pgsql", "e72c03c60bfcb56bbb5d259342021d9cb3581dac"}}];
+ [{p1_pgsql, ".*", {git, "https://github.com/processone/pgsql"}}];
({sqlite, true}) ->
- [{sqlite3, ".*", {git, "https://github.com/alexeyr/erlang-sqlite3", "8350dc603804c503f99c92bfd2eab1dd6885758e"}}];
+ [{sqlite3, ".*", {git, "https://github.com/alexeyr/erlang-sqlite3"}}];
({pam, true}) ->
- [{p1_pam, ".*", {git, "https://github.com/processone/epam", "d3ce290b7da75d780a03e86e7a8198a80e9826a6"}}];
+ [{p1_pam, ".*", {git, "https://github.com/processone/epam"}}];
({zlib, true}) ->
- [{p1_zlib, ".*", {git, "https://github.com/processone/zlib", "e3d4222b7aae616d7ef2e7e2fa0bbf451516c602"}}];
+ [{p1_zlib, ".*", {git, "https://github.com/processone/zlib"}}];
({riak, true}) ->
[{riakc, ".*", {git, "https://github.com/basho/riak-erlang-client", {tag, "1.4.2"}}}];
({elixir, true}) ->
- [{rebar_elixir_plugin, ".*", {git, "https://github.com/yrashk/rebar_elixir_plugin", "7058379b7c7e017555647f6b9cecfd87cd50f884"}},
- {elixir, ".*", {git, "https://github.com/elixir-lang/elixir", "1d9548fd285d243721b7eba71912bde2ffd1f6c3"}}];
+ [{rebar_elixir_plugin, ".*", {git, "https://github.com/yrashk/rebar_elixir_plugin"}},
+ {elixir, ".*", {git, "https://github.com/elixir-lang/elixir", {branch, "v1.0"}}}];
({iconv, true}) ->
- [{p1_iconv, ".*", {git, "https://github.com/processone/eiconv", "8b7542b1aaf0a851f335e464956956985af6d9a2"}}];
+ [{p1_iconv, ".*", {git, "https://github.com/processone/eiconv"}}];
({lager, true}) ->
- [{lager, ".*", {git, "https://github.com/basho/lager", "4d2ec8c701e1fa2d386f92f2b83b23faf8608ac3"}}];
+ [{lager, ".*", {git, "https://github.com/basho/lager"}}];
({lager, false}) ->
- [{p1_logger, ".*", {git, "https://github.com/processone/p1_logger", "3e19507fd5606a73694917158767ecb3f5704e3f"}}];
+ [{p1_logger, ".*", {git, "https://github.com/processone/p1_logger"}}];
({tools, true}) ->
- [{meck, "0.*", {git, "https://github.com/eproxus/meck", "0845277398b8326f9dddddd9fc3cf73467ba6877"}}];
+ [{meck, "0.*", {git, "https://github.com/eproxus/meck"}}];
({redis, true}) ->
- [{eredis, ".*", {git, "https://github.com/wooga/eredis", "bf12ecb30253c84a2331f4f0d93fd68856fcb9f4"}}];
+ [{eredis, ".*", {git, "https://github.com/wooga/eredis"}}];
(_) ->
[]
end, Cfg),
diff --git a/src/ejabberd_admin.erl b/src/ejabberd_admin.erl
index c51a2754..49042f4d 100644
--- a/src/ejabberd_admin.erl
+++ b/src/ejabberd_admin.erl
@@ -143,7 +143,7 @@ commands() ->
args = [],
result = {vhosts, {list, {vhost, string}}}},
#ejabberd_commands{name = reload_config, tags = [server],
- desc = "Reload ejabberd configuration file into memory",
+ desc = "Reload config file in memory (only affects ACL and Access)",
module = ?MODULE, function = reload_config,
args = [],
result = {res, rescode}},
diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl
index 657785ff..ad51db7e 100644
--- a/src/ejabberd_app.erl
+++ b/src/ejabberd_app.erl
@@ -43,6 +43,7 @@
start(normal, _Args) ->
ejabberd_logger:start(),
write_pid_file(),
+ jlib:start(),
start_apps(),
ejabberd:check_app(ejabberd),
randoms:start(),
diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl
index 69b46523..57cf5064 100644
--- a/src/ejabberd_c2s.erl
+++ b/src/ejabberd_c2s.erl
@@ -129,15 +129,6 @@
-endif.
-%% Module start with or without supervisor:
--ifdef(NO_TRANSIENT_SUPERVISORS).
--define(SUPERVISOR_START, ?GEN_FSM:start(ejabberd_c2s, [SockData, Opts],
- fsm_limit_opts(Opts) ++ ?FSMOPTS)).
--else.
--define(SUPERVISOR_START, supervisor:start_child(ejabberd_c2s_sup,
- [SockData, Opts])).
--endif.
-
%% This is the timeout to apply between event when starting a new
%% session:
-define(C2S_OPEN_TIMEOUT, 60000).
@@ -201,7 +192,9 @@
%%% API
%%%----------------------------------------------------------------------
start(SockData, Opts) ->
- ?SUPERVISOR_START.
+ ?GEN_FSM:start(ejabberd_c2s,
+ [SockData, Opts],
+ fsm_limit_opts(Opts) ++ ?FSMOPTS).
start_link(SockData, Opts) ->
(?GEN_FSM):start_link(ejabberd_c2s,
diff --git a/src/ejabberd_http.erl b/src/ejabberd_http.erl
index d2649846..98567777 100644
--- a/src/ejabberd_http.erl
+++ b/src/ejabberd_http.erl
@@ -287,16 +287,18 @@ process_header(State, Data) ->
HostProvided),
State2 = State#state{request_host = Host,
request_port = Port, request_tp = TP},
- Out = process_request(State2),
- send_text(State2, Out),
- case State2#state.request_keepalive of
+ {State3, Out} = process_request(State2),
+ send_text(State3, Out),
+ case State3#state.request_keepalive of
true ->
#state{sockmod = SockMod, socket = Socket,
+ trail = State3#state.trail,
options = State#state.options,
default_host = State#state.default_host,
request_handlers = State#state.request_handlers};
_ ->
#state{end_of_request = true,
+ trail = State3#state.trail,
options = State#state.options,
default_host = State#state.default_host,
request_handlers = State#state.request_handlers}
@@ -366,20 +368,20 @@ process(Handlers, Request, Socket, SockMod, Trail) ->
end.
extract_path_query(#state{request_method = Method,
- request_path = {abs_path, Path}})
+ request_path = {abs_path, Path}} = State)
when Method =:= 'GET' orelse
Method =:= 'HEAD' orelse
Method =:= 'DELETE' orelse Method =:= 'OPTIONS' ->
case catch url_decode_q_split(Path) of
- {'EXIT', _} -> false;
- {NPath, Query} ->
- LPath = normalize_path([NPE
- || NPE <- str:tokens(path_decode(NPath), <<"/">>)]),
- LQuery = case catch parse_urlencoded(Query) of
- {'EXIT', _Reason} -> [];
- LQ -> LQ
- end,
- {LPath, LQuery, <<"">>}
+ {'EXIT', _} -> {State, false};
+ {NPath, Query} ->
+ LPath = normalize_path([NPE
+ || NPE <- str:tokens(path_decode(NPath), <<"/">>)]),
+ LQuery = case catch parse_urlencoded(Query) of
+ {'EXIT', _Reason} -> [];
+ LQ -> LQ
+ end,
+ {State, {LPath, LQuery, <<"">>}}
end;
extract_path_query(#state{request_method = Method,
request_path = {abs_path, Path},
@@ -388,21 +390,21 @@ extract_path_query(#state{request_method = Method,
socket = _Socket} = State)
when (Method =:= 'POST' orelse Method =:= 'PUT') andalso
is_integer(Len) ->
- Data = recv_data(State, Len),
+ {NewState, Data} = recv_data(State, Len),
?DEBUG("client data: ~p~n", [Data]),
case catch url_decode_q_split(Path) of
- {'EXIT', _} -> false;
- {NPath, _Query} ->
- LPath = normalize_path([NPE
- || NPE <- str:tokens(path_decode(NPath), <<"/">>)]),
- LQuery = case catch parse_urlencoded(Data) of
- {'EXIT', _Reason} -> [];
- LQ -> LQ
- end,
- {LPath, LQuery, Data}
+ {'EXIT', _} -> {NewState, false};
+ {NPath, _Query} ->
+ LPath = normalize_path([NPE
+ || NPE <- str:tokens(path_decode(NPath), <<"/">>)]),
+ LQuery = case catch parse_urlencoded(Data) of
+ {'EXIT', _Reason} -> [];
+ LQ -> LQ
+ end,
+ {NewState, {LPath, LQuery, Data}}
end;
-extract_path_query(_State) ->
- false.
+extract_path_query(State) ->
+ {State, false}.
process_request(#state{request_method = Method,
request_auth = Auth,
@@ -417,9 +419,9 @@ process_request(#state{request_method = Method,
request_handlers = RequestHandlers,
trail = Trail} = State) ->
case extract_path_query(State) of
- false ->
- make_bad_request(State);
- {LPath, LQuery, Data} ->
+ {State2, false} ->
+ {State2, make_bad_request(State)};
+ {State2, {LPath, LQuery, Data}} ->
PeerName =
case SockMod of
gen_tcp ->
@@ -445,23 +447,24 @@ process_request(#state{request_method = Method,
opts = Options,
headers = RequestHeaders,
ip = IP},
- case process(RequestHandlers, Request, Socket, SockMod, Trail) of
- El when is_record(El, xmlel) ->
- make_xhtml_output(State, 200, [], El);
- {Status, Headers, El}
- when is_record(El, xmlel) ->
- make_xhtml_output(State, Status, Headers, El);
- Output when is_binary(Output) or is_list(Output) ->
- make_text_output(State, 200, [], Output);
- {Status, Headers, Output}
- when is_binary(Output) or is_list(Output) ->
- make_text_output(State, Status, Headers, Output);
- {Status, Reason, Headers, Output}
- when is_binary(Output) or is_list(Output) ->
- make_text_output(State, Status, Reason, Headers, Output);
- _ ->
- none
- end
+ Res = case process(RequestHandlers, Request, Socket, SockMod, Trail) of
+ El when is_record(El, xmlel) ->
+ make_xhtml_output(State, 200, [], El);
+ {Status, Headers, El}
+ when is_record(El, xmlel) ->
+ make_xhtml_output(State, Status, Headers, El);
+ Output when is_binary(Output) or is_list(Output) ->
+ make_text_output(State, 200, [], Output);
+ {Status, Headers, Output}
+ when is_binary(Output) or is_list(Output) ->
+ make_text_output(State, Status, Headers, Output);
+ {Status, Reason, Headers, Output}
+ when is_binary(Output) or is_list(Output) ->
+ make_text_output(State, Status, Reason, Headers, Output);
+ _ ->
+ none
+ end,
+ {State2, Res}
end.
make_bad_request(State) ->
@@ -501,21 +504,24 @@ is_ipchain_trusted(UserIPs, TrustedIPs) ->
recv_data(State, Len) -> recv_data(State, Len, <<>>).
-recv_data(_State, 0, Acc) -> (iolist_to_binary(Acc));
+recv_data(State, 0, Acc) -> {State, Acc};
+recv_data(#state{trail = Trail} = State, Len, <<>>) when byte_size(Trail) > Len ->
+ <<Data:Len/binary, Rest/binary>> = Trail,
+ {State#state{trail = Rest}, Data};
recv_data(State, Len, Acc) ->
case State#state.trail of
- <<>> ->
- case (State#state.sockmod):recv(State#state.socket, Len,
- 300000)
- of
- {ok, Data} ->
- recv_data(State, Len - byte_size(Data), <<Acc/binary, Data/binary>>);
- _ -> <<"">>
- end;
- _ ->
- Trail = (State#state.trail),
- recv_data(State#state{trail = <<>>},
- Len - byte_size(Trail), <<Acc/binary, Trail/binary>>)
+ <<>> ->
+ case (State#state.sockmod):recv(State#state.socket, Len,
+ 300000)
+ of
+ {ok, Data} ->
+ recv_data(State, Len - byte_size(Data), <<Acc/binary, Data/binary>>);
+ _ -> <<"">>
+ end;
+ _ ->
+ Trail = (State#state.trail),
+ recv_data(State#state{trail = <<>>},
+ Len - byte_size(Trail), <<Acc/binary, Trail/binary>>)
end.
make_xhtml_output(State, Status, Headers, XHTML) ->
diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl
index 0bea9c97..bebb15c4 100644
--- a/src/ejabberd_listener.erl
+++ b/src/ejabberd_listener.erl
@@ -225,8 +225,8 @@ listen_tcp(PortIP, Module, SockOpts, Port, IPS) ->
%% so the option inet/inet6 is only used when no IP is specified at all.
parse_listener_portip(PortIP, Opts) ->
{IPOpt, Opts2} = strip_ip_option(Opts),
- {IPVOpt, OptsClean} = case lists:member(inet6, Opts2) of
- true -> {inet6, Opts2 -- [inet6]};
+ {IPVOpt, OptsClean} = case proplists:get_bool(inet6, Opts2) of
+ true -> {inet6, proplists:delete(inet6, Opts2)};
false -> {inet, Opts2}
end,
{Port, IPT, IPS, Proto} =
@@ -569,11 +569,8 @@ transform_option({{Port, IP, Transport}, Mod, Opts}) ->
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};
+ (A) when is_atom(A) -> {A, true};
(Opt) -> Opt
end, Opts),
Opts2 = lists:foldl(
@@ -593,11 +590,11 @@ transform_option({{Port, IP, Transport}, Mod, Opts}) ->
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, all_zero_ip(Opts), 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({{Port, all_zero_ip(Opts), tcp}, Mod, Opts});
transform_option(Opt) ->
Opt.
@@ -633,7 +630,7 @@ validate_cfg(L) ->
{Port, prepare_mod(Mod), Opts};
(Opt, {Port, Mod, Opts}) ->
{Port, Mod, [Opt|Opts]}
- end, {{5222, {0,0,0,0}, tcp}, ejabberd_c2s, []}, LOpts)
+ end, {{5222, all_zero_ip(LOpts), tcp}, ejabberd_c2s, []}, LOpts)
end, L).
prepare_ip({A, B, C, D} = IP)
@@ -656,5 +653,11 @@ prepare_mod(sip) ->
prepare_mod(Mod) when is_atom(Mod) ->
Mod.
+all_zero_ip(Opts) ->
+ case proplists:get_bool(inet6, Opts) of
+ true -> {0,0,0,0,0,0,0,0};
+ false -> {0,0,0,0}
+ end.
+
opt_type(listen) -> fun validate_cfg/1;
opt_type(_) -> [listen].
diff --git a/src/ejabberd_receiver.erl b/src/ejabberd_receiver.erl
index cd7c1d31..71ae8e40 100644
--- a/src/ejabberd_receiver.erl
+++ b/src/ejabberd_receiver.erl
@@ -127,20 +127,10 @@ init([Socket, SockMod, Shaper, MaxStanzaSize]) ->
shaper_state = ShaperState,
max_stanza_size = MaxStanzaSize, timeout = Timeout}}.
-handle_call({starttls, TLSSocket}, _From,
- #state{xml_stream_state = XMLStreamState,
- c2s_pid = C2SPid,
- max_stanza_size = MaxStanzaSize} = State) ->
- close_stream(XMLStreamState),
- NewXMLStreamState = case C2SPid of
- undefined ->
- XMLStreamState;
- _ ->
- xml_stream:new(C2SPid, MaxStanzaSize)
- end,
- NewState = State#state{socket = TLSSocket,
- sock_mod = p1_tls,
- xml_stream_state = NewXMLStreamState},
+handle_call({starttls, TLSSocket}, _From, State) ->
+ State1 = reset_parser(State),
+ NewState = State1#state{socket = TLSSocket,
+ sock_mod = p1_tls},
case p1_tls:recv_data(TLSSocket, <<"">>) of
{ok, TLSData} ->
{reply, ok,
@@ -149,20 +139,16 @@ handle_call({starttls, TLSSocket}, _From,
{stop, normal, ok, NewState}
end;
handle_call({compress, Data}, _From,
- #state{xml_stream_state = XMLStreamState,
- c2s_pid = C2SPid, socket = Socket, sock_mod = SockMod,
- max_stanza_size = MaxStanzaSize} =
+ #state{socket = Socket, sock_mod = SockMod} =
State) ->
{ok, ZlibSocket} = ezlib:enable_zlib(SockMod,
Socket),
if Data /= undefined -> do_send(State, Data);
true -> ok
end,
- close_stream(XMLStreamState),
- NewXMLStreamState = xml_stream:new(C2SPid, MaxStanzaSize),
- NewState = State#state{socket = ZlibSocket,
- sock_mod = ezlib,
- xml_stream_state = NewXMLStreamState},
+ State1 = reset_parser(State),
+ NewState = State1#state{socket = ZlibSocket,
+ sock_mod = ezlib},
case ezlib:recv_data(ZlibSocket, <<"">>) of
{ok, ZlibData} ->
{reply, {ok, ZlibSocket},
@@ -170,16 +156,10 @@ handle_call({compress, Data}, _From,
{error, _Reason} ->
{stop, normal, ok, NewState}
end;
-handle_call(reset_stream, _From,
- #state{xml_stream_state = XMLStreamState,
- c2s_pid = C2SPid, max_stanza_size = MaxStanzaSize} =
- State) ->
- close_stream(XMLStreamState),
- NewXMLStreamState = xml_stream:new(C2SPid, MaxStanzaSize),
+handle_call(reset_stream, _From, State) ->
+ NewState = reset_parser(State),
Reply = ok,
- {reply, Reply,
- State#state{xml_stream_state = NewXMLStreamState},
- ?HIBERNATE_TIMEOUT};
+ {reply, Reply, NewState, ?HIBERNATE_TIMEOUT};
handle_call({become_controller, C2SPid}, _From, State) ->
XMLStreamState = xml_stream:new(C2SPid, State#state.max_stanza_size),
NewState = State#state{c2s_pid = C2SPid,
@@ -332,6 +312,24 @@ close_stream(undefined) -> ok;
close_stream(XMLStreamState) ->
xml_stream:close(XMLStreamState).
+reset_parser(#state{xml_stream_state = undefined} = State) ->
+ State;
+reset_parser(#state{c2s_pid = C2SPid,
+ max_stanza_size = MaxStanzaSize,
+ xml_stream_state = XMLStreamState}
+ = State) ->
+ NewStreamState = try xml_stream:reset(XMLStreamState)
+ catch error:_ ->
+ close_stream(XMLStreamState),
+ case C2SPid of
+ undefined ->
+ undefined;
+ _ ->
+ xml_stream:new(C2SPid, MaxStanzaSize)
+ end
+ end,
+ State#state{xml_stream_state = NewStreamState}.
+
do_send(State, Data) ->
(State#state.sock_mod):send(State#state.socket, Data).
diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl
index d840c315..e655397b 100644
--- a/src/ejabberd_s2s_in.erl
+++ b/src/ejabberd_s2s_in.erl
@@ -74,21 +74,6 @@
-endif.
-%% Module start with or without supervisor:
--ifdef(NO_TRANSIENT_SUPERVISORS).
-
--define(SUPERVISOR_START,
- p1_fsm:start(ejabberd_s2s_in, [SockData, Opts],
- ?FSMOPTS ++ fsm_limit_opts(Opts))).
-
--else.
-
--define(SUPERVISOR_START,
- supervisor:start_child(ejabberd_s2s_in_sup,
- [SockData, Opts])).
-
--endif.
-
-define(STREAM_HEADER(Version),
<<"<?xml version='1.0'?><stream:stream "
"xmlns:stream='http://etherx.jabber.org/stream"
@@ -111,7 +96,9 @@
-define(INVALID_XML_ERR,
xml:element_to_binary(?SERR_XML_NOT_WELL_FORMED)).
-start(SockData, Opts) -> ?SUPERVISOR_START.
+start(SockData, Opts) ->
+ supervisor:start_child(ejabberd_s2s_in_sup,
+ [SockData, Opts]).
start_link(SockData, Opts) ->
p1_fsm:start_link(ejabberd_s2s_in, [SockData, Opts],
diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl
index bc815166..73aa10ff 100644
--- a/src/ejabberd_s2s_out.erl
+++ b/src/ejabberd_s2s_out.erl
@@ -86,15 +86,6 @@
-endif.
-%% Module start with or without supervisor:
--ifdef(NO_TRANSIENT_SUPERVISORS).
--define(SUPERVISOR_START, p1_fsm:start(ejabberd_s2s_out, [From, Host, Type],
- fsm_limit_opts() ++ ?FSMOPTS)).
--else.
--define(SUPERVISOR_START, supervisor:start_child(ejabberd_s2s_out_sup,
- [From, Host, Type])).
--endif.
-
-define(FSMTIMEOUT, 30000).
%% We do not block on send anymore.
@@ -127,7 +118,8 @@
%%% API
%%%----------------------------------------------------------------------
start(From, Host, Type) ->
- ?SUPERVISOR_START.
+ supervisor:start_child(ejabberd_s2s_out_sup,
+ [From, Host, Type]).
start_link(From, Host, Type) ->
p1_fsm:start_link(ejabberd_s2s_out, [From, Host, Type],
diff --git a/src/ejabberd_sup.erl b/src/ejabberd_sup.erl
index da25af2c..e8d3ce83 100644
--- a/src/ejabberd_sup.erl
+++ b/src/ejabberd_sup.erl
@@ -105,13 +105,6 @@ init([]) ->
infinity,
supervisor,
[ejabberd_tmp_sup]},
- C2SSupervisor =
- {ejabberd_c2s_sup,
- {ejabberd_tmp_sup, start_link, [ejabberd_c2s_sup, ejabberd_c2s]},
- permanent,
- infinity,
- supervisor,
- [ejabberd_tmp_sup]},
S2SInSupervisor =
{ejabberd_s2s_in_sup,
{ejabberd_tmp_sup, start_link,
@@ -170,7 +163,6 @@ init([]) ->
Local,
Captcha,
ReceiverSupervisor,
- C2SSupervisor,
S2SInSupervisor,
S2SOutSupervisor,
ServiceSupervisor,
diff --git a/src/jlib.erl b/src/jlib.erl
index cc0f826a..52dd9b2c 100644
--- a/src/jlib.erl
+++ b/src/jlib.erl
@@ -58,11 +58,19 @@
atom_to_binary/1, binary_to_atom/1, tuple_to_binary/1,
l2i/1, i2l/1, i2l/2, queue_drop_while/2]).
+-export([start/0]).
+
-include("ejabberd.hrl").
-include("jlib.hrl").
-export_type([jid/0]).
+start() ->
+ SplitPattern = binary:compile_pattern([<<"@">>, <<"/">>]),
+ catch ets:new(jlib, [named_table, protected, set, {keypos, 1}]),
+ ets:insert(jlib, {string_to_jid_pattern, SplitPattern}),
+ ok.
+
%send_iq(From, To, ID, SubTags) ->
% ok.
@@ -215,7 +223,7 @@ make_jid({User, Server, Resource}) ->
make_jid(User, Server, Resource).
%% This is the reverse of make_jid/1
--spec split_jid(jid()) -> {binary(), binary(), binary()} | error.
+-spec split_jid(jid()) -> {binary(), binary(), binary()} | error.
split_jid(#jid{user = U, server = S, resource = R}) ->
{U, S, R};
split_jid(_) ->
@@ -224,36 +232,44 @@ split_jid(_) ->
-spec string_to_jid(binary()) -> jid() | error.
string_to_jid(S) ->
- string_to_jid1(binary_to_list(S), "").
-
-string_to_jid1([$@ | _J], "") -> error;
-string_to_jid1([$@ | J], N) ->
- string_to_jid2(J, lists:reverse(N), "");
-string_to_jid1([$/ | _J], "") -> error;
-string_to_jid1([$/ | J], N) ->
- string_to_jid3(J, "", lists:reverse(N), "");
-string_to_jid1([C | J], N) ->
- string_to_jid1(J, [C | N]);
-string_to_jid1([], "") -> error;
-string_to_jid1([], N) ->
- make_jid(<<"">>, list_to_binary(lists:reverse(N)), <<"">>).
-
-%% Only one "@" is admitted per JID
-string_to_jid2([$@ | _J], _N, _S) -> error;
-string_to_jid2([$/ | _J], _N, "") -> error;
-string_to_jid2([$/ | J], N, S) ->
- string_to_jid3(J, N, lists:reverse(S), "");
-string_to_jid2([C | J], N, S) ->
- string_to_jid2(J, N, [C | S]);
-string_to_jid2([], _N, "") -> error;
-string_to_jid2([], N, S) ->
- make_jid(list_to_binary(N), list_to_binary(lists:reverse(S)), <<"">>).
-
-string_to_jid3([C | J], N, S, R) ->
- string_to_jid3(J, N, S, [C | R]);
-string_to_jid3([], N, S, R) ->
- make_jid(list_to_binary(N), list_to_binary(S),
- list_to_binary(lists:reverse(R))).
+ SplitPattern = ets:lookup_element(jlib, string_to_jid_pattern, 2),
+ Size = size(S),
+ End = Size-1,
+ case binary:match(S, SplitPattern) of
+ {0, _} ->
+ error;
+ {End, _} ->
+ error;
+ {Pos1, _} ->
+ case binary:at(S, Pos1) of
+ $/ ->
+ make_jid(<<>>,
+ binary:part(S, 0, Pos1),
+ binary:part(S, Pos1+1, Size-Pos1-1));
+ _ ->
+ Pos1N = Pos1+1,
+ case binary:match(S, SplitPattern, [{scope, {Pos1+1, Size-Pos1-1}}]) of
+ {End, _} ->
+ error;
+ {Pos1N, _} ->
+ error;
+ {Pos2, _} ->
+ case binary:at(S, Pos2) of
+ $/ ->
+ make_jid(binary:part(S, 0, Pos1),
+ binary:part(S, Pos1+1, Pos2-Pos1-1),
+ binary:part(S, Pos2+1, Size-Pos2-1));
+ _ -> error
+ end;
+ _ ->
+ make_jid(binary:part(S, 0, Pos1),
+ binary:part(S, Pos1+1, Size-Pos1-1),
+ <<>>)
+ end
+ end;
+ _ ->
+ make_jid(<<>>, S, <<>>)
+ end.
-spec jid_to_string(jid() | ljid()) -> binary().
@@ -856,7 +872,7 @@ decode_base64(S) ->
decode_base64_bin(S, <<>>)
end.
-take_without_spaces(Bin, Count) ->
+take_without_spaces(Bin, Count) ->
take_without_spaces(Bin, Count, <<>>).
take_without_spaces(Bin, 0, Acc) ->
diff --git a/src/mod_client_state.erl b/src/mod_client_state.erl
index eb40db10..4934db3b 100644
--- a/src/mod_client_state.erl
+++ b/src/mod_client_state.erl
@@ -1,8 +1,8 @@
%%%----------------------------------------------------------------------
%%% File : mod_client_state.erl
-%%% Author : Holger Weiss
+%%% Author : Holger Weiss <holger@zedat.fu-berlin.de>
%%% Purpose : Filter stanzas sent to inactive clients (XEP-0352)
-%%% Created : 11 Sep 2014 by Holger Weiss
+%%% Created : 11 Sep 2014 by Holger Weiss <holger@zedat.fu-berlin.de>
%%%
%%%
%%% ejabberd, Copyright (C) 2014-2015 ProcessOne
diff --git a/src/mod_http_upload.erl b/src/mod_http_upload.erl
index 35fd6ca3..87707790 100644
--- a/src/mod_http_upload.erl
+++ b/src/mod_http_upload.erl
@@ -1,13 +1,33 @@
-%%%-------------------------------------------------------------------
+%%%----------------------------------------------------------------------
%%% File : mod_http_upload.erl
%%% Author : Holger Weiss <holger@zedat.fu-berlin.de>
%%% Purpose : HTTP File Upload (XEP-0363)
%%% Created : 20 Aug 2015 by Holger Weiss <holger@zedat.fu-berlin.de>
-%%%-------------------------------------------------------------------
+%%%
+%%%
+%%% ejabberd, Copyright (C) 2015 ProcessOne
+%%%
+%%% This program is free software; you can redistribute it and/or
+%%% modify it under the terms of the GNU General Public License as
+%%% published by the Free Software Foundation; either version 2 of the
+%%% License, or (at your option) any later version.
+%%%
+%%% This program is distributed in the hope that it will be useful,
+%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+%%% General Public License for more details.
+%%%
+%%% You should have received a copy of the GNU General Public License along
+%%% with this program; if not, write to the Free Software Foundation, Inc.,
+%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+%%%
+%%%----------------------------------------------------------------------
-module(mod_http_upload).
-author('holger@zedat.fu-berlin.de').
+-protocol({xep, 363, '0.1'}).
+
-define(GEN_SERVER, gen_server).
-define(SERVICE_REQUEST_TIMEOUT, 5000). % 5 seconds.
-define(SLOT_TIMEOUT, 18000000). % 5 hours.
@@ -92,12 +112,12 @@
slots = dict:new() :: term()}). % dict:dict() requires Erlang 17.
-record(media_info,
- {type :: string(),
+ {type :: binary(),
height :: integer(),
width :: integer()}).
-type state() :: #state{}.
--type slot() :: [binary()].
+-type slot() :: [binary(), ...].
-type media_info() :: #media_info{}.
%%--------------------------------------------------------------------
@@ -116,12 +136,13 @@ start(ServerHost, Opts) ->
case gen_mod:get_opt(rm_on_unregister, Opts,
fun(B) when is_boolean(B) -> B end,
true) of
- true ->
- ejabberd_hooks:add(remove_user, ServerHost, ?MODULE,
- remove_user, 50),
- ejabberd_hooks:add(anonymous_purge_hook, ServerHost, ?MODULE,
- remove_user, 50);
- false -> ok
+ true ->
+ ejabberd_hooks:add(remove_user, ServerHost, ?MODULE,
+ remove_user, 50),
+ ejabberd_hooks:add(anonymous_purge_hook, ServerHost, ?MODULE,
+ remove_user, 50);
+ false ->
+ ok
end,
Proc = get_proc_name(ServerHost, ?PROCNAME),
Spec = {Proc,
@@ -138,16 +159,17 @@ stop(ServerHost) ->
case gen_mod:get_module_opt(ServerHost, ?MODULE, rm_on_unregister,
fun(B) when is_boolean(B) -> B end,
true) of
- true ->
- ejabberd_hooks:delete(remove_user, ServerHost, ?MODULE,
- remove_user, 50),
- ejabberd_hooks:delete(anonymous_purge_hook, ServerHost, ?MODULE,
- remove_user, 50);
- false -> ok
+ true ->
+ ejabberd_hooks:delete(remove_user, ServerHost, ?MODULE,
+ remove_user, 50),
+ ejabberd_hooks:delete(anonymous_purge_hook, ServerHost, ?MODULE,
+ remove_user, 50);
+ false ->
+ ok
end,
Proc = get_proc_name(ServerHost, ?PROCNAME),
- ok = supervisor:terminate_child(ejabberd_sup, Proc),
- ok = supervisor:delete_child(ejabberd_sup, Proc).
+ supervisor:terminate_child(ejabberd_sup, Proc),
+ supervisor:delete_child(ejabberd_sup, Proc).
-spec mod_opt_type(atom()) -> fun((term()) -> term()) | [atom()].
@@ -253,22 +275,34 @@ init({ServerHost, Opts}) ->
fun(B) when is_boolean(B) -> B end,
true),
case ServiceURL of
- undefined ->
- ok;
- <<"http://", _/binary>> ->
- application:start(inets);
- <<"https://", _/binary>> ->
- application:start(inets),
- application:start(crypto),
- application:start(asn1),
- application:start(public_key),
- application:start(ssl)
+ undefined ->
+ ok;
+ <<"http://", _/binary>> ->
+ application:start(inets);
+ <<"https://", _/binary>> ->
+ application:start(inets),
+ application:start(crypto),
+ application:start(asn1),
+ application:start(public_key),
+ application:start(ssl)
end,
case DirMode of
- undefined ->
- ok;
- Mode ->
- file:change_mode(DocRoot, Mode)
+ undefined ->
+ ok;
+ Mode ->
+ file:change_mode(DocRoot, Mode)
+ end,
+ case Thumbnail of
+ true ->
+ case string:str(os:cmd("identify"), "Magick") of
+ 0 ->
+ ?ERROR_MSG("Cannot find 'identify' command, please install "
+ "ImageMagick or disable thumbnail creation", []);
+ _ ->
+ ok
+ end;
+ false ->
+ ok
end,
ejabberd_router:register_route(Host),
{ok, #state{server_host = ServerHost, host = Host, name = Name,
@@ -293,14 +327,14 @@ handle_call({use_slot, Slot}, _From, #state{file_mode = FileMode,
thumbnail = Thumbnail,
docroot = DocRoot} = State) ->
case get_slot(Slot, State) of
- {ok, {Size, Timer}} ->
- timer:cancel(Timer),
- NewState = del_slot(Slot, State),
- Path = str:join([DocRoot | Slot], <<$/>>),
- {reply, {ok, Size, Path, FileMode, DirMode, GetPrefix, Thumbnail},
- NewState};
- error ->
- {reply, {error, <<"Invalid slot">>}, State}
+ {ok, {Size, Timer}} ->
+ timer:cancel(Timer),
+ NewState = del_slot(Slot, State),
+ Path = str:join([DocRoot | Slot], <<$/>>),
+ {reply, {ok, Size, Path, FileMode, DirMode, GetPrefix, Thumbnail},
+ NewState};
+ error ->
+ {reply, {error, <<"Invalid slot">>}, State}
end;
handle_call(get_docroot, _From, #state{docroot = DocRoot} = State) ->
{reply, {ok, DocRoot}, State};
@@ -319,12 +353,12 @@ handle_cast(Request, State) ->
handle_info({route, From, To, #xmlel{name = <<"iq">>} = Stanza}, State) ->
Request = jlib:iq_query_info(Stanza),
{Reply, NewState} = case process_iq(From, Request, State) of
- R when is_record(R, iq) ->
- {R, State};
- {R, S} ->
- {R, S};
- not_request ->
- {none, State}
+ R when is_record(R, iq) ->
+ {R, State};
+ {R, S} ->
+ {R, S};
+ not_request ->
+ {none, State}
end,
if Reply /= none ->
ejabberd_router:route(To, From, jlib:iq_to_xml(Reply));
@@ -359,82 +393,95 @@ code_change(_OldVsn, #state{server_host = ServerHost} = State, _Extra) ->
-spec process([binary()], #request{})
-> {pos_integer(), [{binary(), binary()}], binary()}.
-process(LocalPath, #request{method = 'PUT', host = Host, ip = IP,
- data = Data}) ->
+process([_UserDir, _RandDir, _FileName] = Slot,
+ #request{method = 'PUT', host = Host, ip = IP, data = Data}) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
- case catch gen_server:call(Proc, {use_slot, LocalPath}) of
- {ok, Size, Path, FileMode, DirMode, GetPrefix, Thumbnail}
- when byte_size(Data) == Size ->
- ?DEBUG("Storing file from ~s for ~s: ~s",
- [?ADDR_TO_STR(IP), Host, Path]),
- case store_file(Path, Data, FileMode, DirMode,
- GetPrefix, LocalPath, Thumbnail) of
- ok ->
- http_response(Host, 201);
- {ok, Headers, OutData} ->
- http_response(Host, 201, Headers, OutData);
- {error, Error} ->
- ?ERROR_MSG("Cannot store file ~s from ~s for ~s: ~p",
- [Path, ?ADDR_TO_STR(IP), Host, Error]),
- http_response(Host, 500)
- end;
- {ok, Size, Path} ->
- ?INFO_MSG("Rejecting file ~s from ~s for ~s: Size is ~B, not ~B",
- [Path, ?ADDR_TO_STR(IP), Host, byte_size(Data), Size]),
- http_response(Host, 413);
- {error, Error} ->
- ?INFO_MSG("Rejecting file from ~s for ~s: ~p",
- [?ADDR_TO_STR(IP), Host, Error]),
- http_response(Host, 403);
- Error ->
- ?ERROR_MSG("Cannot handle PUT request from ~s for ~s: ~p",
- [?ADDR_TO_STR(IP), Host, Error]),
- http_response(Host, 500)
+ case catch gen_server:call(Proc, {use_slot, Slot}) of
+ {ok, Size, Path, FileMode, DirMode, GetPrefix, Thumbnail}
+ when byte_size(Data) == Size ->
+ ?DEBUG("Storing file from ~s for ~s: ~s",
+ [?ADDR_TO_STR(IP), Host, Path]),
+ case store_file(Path, Data, FileMode, DirMode,
+ GetPrefix, Slot, Thumbnail) of
+ ok ->
+ http_response(Host, 201);
+ {ok, Headers, OutData} ->
+ http_response(Host, 201, Headers, OutData);
+ {error, Error} ->
+ ?ERROR_MSG("Cannot store file ~s from ~s for ~s: ~p",
+ [Path, ?ADDR_TO_STR(IP), Host, ?FORMAT(Error)]),
+ http_response(Host, 500)
+ end;
+ {ok, Size, Path} ->
+ ?INFO_MSG("Rejecting file ~s from ~s for ~s: Size is ~B, not ~B",
+ [Path, ?ADDR_TO_STR(IP), Host, byte_size(Data), Size]),
+ http_response(Host, 413);
+ {error, Error} ->
+ ?INFO_MSG("Rejecting file from ~s for ~s: ~p",
+ [?ADDR_TO_STR(IP), Host, Error]),
+ http_response(Host, 403);
+ Error ->
+ ?ERROR_MSG("Cannot handle PUT request from ~s for ~s: ~p",
+ [?ADDR_TO_STR(IP), Host, Error]),
+ http_response(Host, 500)
end;
-process(LocalPath, #request{method = Method, host = Host, ip = IP})
+process([_UserDir, _RandDir, FileName] = Slot,
+ #request{method = Method, host = Host, ip = IP})
when Method == 'GET';
Method == 'HEAD' ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
case catch gen_server:call(Proc, get_docroot) of
- {ok, DocRoot} ->
- Path = str:join([DocRoot | LocalPath], <<$/>>),
- case file:read_file(Path) of
- {ok, Data} ->
- ?INFO_MSG("Serving ~s to ~s", [Path, ?ADDR_TO_STR(IP)]),
- FileName = lists:last(LocalPath),
- ContentType = guess_content_type(FileName),
- Headers1 = case ContentType of
- <<"image/", _SubType/binary>> -> [];
- <<"text/", _SubType/binary>> -> [];
- _ ->
- [{<<"Content-Disposition">>,
- <<"attachment; filename=",
- $", FileName/binary, $">>}]
- end,
- Headers2 = [{<<"Content-Type">>, ContentType} | Headers1],
- http_response(Host, 200, Headers2, Data);
- {error, eacces} ->
- ?INFO_MSG("Cannot serve ~s to ~s: Permission denied",
- [Path, ?ADDR_TO_STR(IP)]),
- http_response(Host, 403);
- {error, enoent} ->
- ?INFO_MSG("Cannot serve ~s to ~s: No such file or directory",
- [Path, ?ADDR_TO_STR(IP)]),
- http_response(Host, 404);
- {error, eisdir} ->
- ?INFO_MSG("Cannot serve ~s to ~s: Is a directory",
- [Path, ?ADDR_TO_STR(IP)]),
- http_response(Host, 404);
- {error, Error} ->
- ?INFO_MSG("Cannot serve ~s to ~s: ~s",
- [Path, ?ADDR_TO_STR(IP), ?FORMAT(Error)]),
- http_response(Host, 500)
- end;
- Error ->
- ?ERROR_MSG("Cannot handle ~s request from ~s for ~s: ~p",
- [Method, ?ADDR_TO_STR(IP), Host, Error]),
- http_response(Host, 500)
+ {ok, DocRoot} ->
+ Path = str:join([DocRoot | Slot], <<$/>>),
+ case file:read_file(Path) of
+ {ok, Data} ->
+ ?INFO_MSG("Serving ~s to ~s", [Path, ?ADDR_TO_STR(IP)]),
+ ContentType = guess_content_type(FileName),
+ Headers1 = case ContentType of
+ <<"image/", _SubType/binary>> -> [];
+ <<"text/", _SubType/binary>> -> [];
+ _ ->
+ [{<<"Content-Disposition">>,
+ <<"attachment; filename=",
+ $", FileName/binary, $">>}]
+ end,
+ Headers2 = [{<<"Content-Type">>, ContentType} | Headers1],
+ http_response(Host, 200, Headers2, Data);
+ {error, eacces} ->
+ ?INFO_MSG("Cannot serve ~s to ~s: Permission denied",
+ [Path, ?ADDR_TO_STR(IP)]),
+ http_response(Host, 403);
+ {error, enoent} ->
+ ?INFO_MSG("Cannot serve ~s to ~s: No such file",
+ [Path, ?ADDR_TO_STR(IP)]),
+ http_response(Host, 404);
+ {error, eisdir} ->
+ ?INFO_MSG("Cannot serve ~s to ~s: Is a directory",
+ [Path, ?ADDR_TO_STR(IP)]),
+ http_response(Host, 404);
+ {error, Error} ->
+ ?INFO_MSG("Cannot serve ~s to ~s: ~s",
+ [Path, ?ADDR_TO_STR(IP), ?FORMAT(Error)]),
+ http_response(Host, 500)
+ end;
+ Error ->
+ ?ERROR_MSG("Cannot handle ~s request from ~s for ~s: ~p",
+ [Method, ?ADDR_TO_STR(IP), Host, Error]),
+ http_response(Host, 500)
end;
+process(LocalPath, #request{method = 'PUT', host = Host, ip = IP})
+ when length(LocalPath) > 3 ->
+ ?INFO_MSG("Rejecting PUT request from ~s for ~s: Too many path components",
+ [?ADDR_TO_STR(IP), Host]),
+ ?INFO_MSG("Check whether 'request_handlers' path matches 'put_url'", []),
+ http_response(Host, 404);
+process(_LocalPath, #request{method = Method, host = Host, ip = IP})
+ when Method == 'PUT';
+ Method == 'GET';
+ Method == 'HEAD' ->
+ ?DEBUG("Rejecting ~s request from ~s for ~s: Too few/many path components",
+ [Method, ?ADDR_TO_STR(IP), Host]),
+ http_response(Host, 404);
process(_LocalPath, #request{method = 'OPTIONS', host = Host, ip = IP}) ->
?DEBUG("Responding to OPTIONS request from ~s for ~s",
[?ADDR_TO_STR(IP), Host]),
@@ -493,31 +540,33 @@ process_iq(From,
when XMLNS == ?NS_HTTP_UPLOAD;
XMLNS == ?NS_HTTP_UPLOAD_OLD ->
case acl:match_rule(ServerHost, Access, From) of
- allow ->
- case parse_request(SubEl, Lang) of
- {ok, File, Size, ContentType} ->
- case create_slot(State, From, File, Size, ContentType, Lang) of
- {ok, Slot} ->
- {ok, Timer} = timer:send_after(?SLOT_TIMEOUT,
- {slot_timed_out, Slot}),
- NewState = add_slot(Slot, Size, Timer, State),
- SlotEl = slot_el(Slot, State, XMLNS),
- {IQ#iq{type = result, sub_el = [SlotEl]}, NewState};
- {ok, PutURL, GetURL} ->
- SlotEl = slot_el(PutURL, GetURL, XMLNS),
- IQ#iq{type = result, sub_el = [SlotEl]};
- {error, Error} ->
- IQ#iq{type = error, sub_el = [SubEl, Error]}
- end;
- {error, Error} ->
- ?DEBUG("Cannot parse request from ~s",
- [jlib:jid_to_string(From)]),
- IQ#iq{type = error, sub_el = [SubEl, Error]}
- end;
- deny ->
- ?DEBUG("Denying HTTP upload slot request from ~s",
- [jlib:jid_to_string(From)]),
- IQ#iq{type = error, sub_el = [SubEl, ?ERR_FORBIDDEN]}
+ allow ->
+ case parse_request(SubEl, Lang) of
+ {ok, File, Size, ContentType} ->
+ case create_slot(State, From, File, Size, ContentType,
+ Lang) of
+ {ok, Slot} ->
+ {ok, Timer} = timer:send_after(?SLOT_TIMEOUT,
+ {slot_timed_out,
+ Slot}),
+ NewState = add_slot(Slot, Size, Timer, State),
+ SlotEl = slot_el(Slot, State, XMLNS),
+ {IQ#iq{type = result, sub_el = [SlotEl]}, NewState};
+ {ok, PutURL, GetURL} ->
+ SlotEl = slot_el(PutURL, GetURL, XMLNS),
+ IQ#iq{type = result, sub_el = [SlotEl]};
+ {error, Error} ->
+ IQ#iq{type = error, sub_el = [SubEl, Error]}
+ end;
+ {error, Error} ->
+ ?DEBUG("Cannot parse request from ~s",
+ [jlib:jid_to_string(From)]),
+ IQ#iq{type = error, sub_el = [SubEl, Error]}
+ end;
+ deny ->
+ ?DEBUG("Denying HTTP upload slot request from ~s",
+ [jlib:jid_to_string(From)]),
+ IQ#iq{type = error, sub_el = [SubEl, ?ERR_FORBIDDEN]}
end;
process_iq(_From, #iq{sub_el = SubEl} = IQ, _State) ->
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
@@ -531,25 +580,25 @@ process_iq(_From, invalid, _State) ->
parse_request(#xmlel{name = <<"request">>, attrs = Attrs} = Request, Lang) ->
case xml:get_attr(<<"xmlns">>, Attrs) of
- {value, XMLNS} when XMLNS == ?NS_HTTP_UPLOAD;
- XMLNS == ?NS_HTTP_UPLOAD_OLD ->
- case {xml:get_subtag_cdata(Request, <<"filename">>),
- xml:get_subtag_cdata(Request, <<"size">>),
- xml:get_subtag_cdata(Request, <<"content-type">>)} of
- {File, SizeStr, ContentType} when byte_size(File) > 0 ->
- case catch jlib:binary_to_integer(SizeStr) of
- Size when is_integer(Size), Size > 0 ->
- {ok, File, Size, yield_content_type(ContentType)};
- _ ->
- Text = <<"Please specify file size.">>,
- {error, ?ERRT_BAD_REQUEST(Lang, Text)}
- end;
- _ ->
- Text = <<"Please specify file name.">>,
- {error, ?ERRT_BAD_REQUEST(Lang, Text)}
- end;
- _ ->
- {error, ?ERR_BAD_REQUEST}
+ {value, XMLNS} when XMLNS == ?NS_HTTP_UPLOAD;
+ XMLNS == ?NS_HTTP_UPLOAD_OLD ->
+ case {xml:get_subtag_cdata(Request, <<"filename">>),
+ xml:get_subtag_cdata(Request, <<"size">>),
+ xml:get_subtag_cdata(Request, <<"content-type">>)} of
+ {File, SizeStr, ContentType} when byte_size(File) > 0 ->
+ case catch jlib:binary_to_integer(SizeStr) of
+ Size when is_integer(Size), Size > 0 ->
+ {ok, File, Size, yield_content_type(ContentType)};
+ _ ->
+ Text = <<"Please specify file size.">>,
+ {error, ?ERRT_BAD_REQUEST(Lang, Text)}
+ end;
+ _ ->
+ Text = <<"Please specify file name.">>,
+ {error, ?ERRT_BAD_REQUEST(Lang, Text)}
+ end;
+ _ ->
+ {error, ?ERR_BAD_REQUEST}
end;
parse_request(_El, _Lang) -> {error, ?ERR_BAD_REQUEST}.
@@ -574,16 +623,16 @@ create_slot(#state{service_url = undefined,
UserDir = <<DocRoot/binary, $/, UserStr/binary>>,
case ejabberd_hooks:run_fold(http_upload_slot_request, ServerHost, allow,
[JID, UserDir, Size, Lang]) of
- allow ->
- RandStr = make_rand_string(SecretLength),
- FileStr = make_file_string(File),
- ?INFO_MSG("Got HTTP upload slot for ~s (file: ~s)",
- [jlib:jid_to_string(JID), File]),
- {ok, [UserStr, RandStr, FileStr]};
- deny ->
- {error, ?ERR_SERVICE_UNAVAILABLE};
- #xmlel{} = Error ->
- {error, Error}
+ allow ->
+ RandStr = make_rand_string(SecretLength),
+ FileStr = make_file_string(File),
+ ?INFO_MSG("Got HTTP upload slot for ~s (file: ~s)",
+ [jlib:jid_to_string(JID), File]),
+ {ok, [UserStr, RandStr, FileStr]};
+ deny ->
+ {error, ?ERR_SERVICE_UNAVAILABLE};
+ #xmlel{} = Error ->
+ {error, Error}
end;
create_slot(#state{service_url = ServiceURL},
#jid{luser = U, lserver = S} = JID, File, Size, ContentType,
@@ -597,37 +646,38 @@ create_slot(#state{service_url = ServiceURL},
"&size=" ++ ?URL_ENC(SizeStr) ++
"&content_type=" ++ ?URL_ENC(ContentType),
case httpc:request(get, {GetRequest, []}, HttpOptions, Options) of
- {ok, {Code, Body}} when Code >= 200, Code =< 299 ->
- case binary:split(Body, <<$\n>>, [global, trim]) of
- [<<"http", _/binary>> = PutURL, <<"http", _/binary>> = GetURL] ->
- ?INFO_MSG("Got HTTP upload slot for ~s (file: ~s)",
- [jlib:jid_to_string(JID), File]),
- {ok, PutURL, GetURL};
- Lines ->
- ?ERROR_MSG("Cannot parse data received for ~s from <~s>: ~p",
- [jlib:jid_to_string(JID), ServiceURL, Lines]),
- {error, ?ERR_SERVICE_UNAVAILABLE}
- end;
- {ok, {402, _Body}} ->
- ?INFO_MSG("Got status code 402 for ~s from <~s>",
- [jlib:jid_to_string(JID), ServiceURL]),
- {error, ?ERR_RESOURCE_CONSTRAINT};
- {ok, {403, _Body}} ->
- ?INFO_MSG("Got status code 403 for ~s from <~s>",
- [jlib:jid_to_string(JID), ServiceURL]),
- {error, ?ERR_NOT_ALLOWED};
- {ok, {413, _Body}} ->
- ?INFO_MSG("Got status code 413 for ~s from <~s>",
- [jlib:jid_to_string(JID), ServiceURL]),
- {error, ?ERR_NOT_ACCEPTABLE};
- {ok, {Code, _Body}} ->
- ?ERROR_MSG("Got unexpected status code for ~s from <~s>: ~B",
- [jlib:jid_to_string(JID), ServiceURL, Code]),
- {error, ?ERR_SERVICE_UNAVAILABLE};
- {error, Reason} ->
- ?ERROR_MSG("Error requesting upload slot for ~s from <~s>: ~p",
- [jlib:jid_to_string(JID), ServiceURL, Reason]),
- {error, ?ERR_SERVICE_UNAVAILABLE}
+ {ok, {Code, Body}} when Code >= 200, Code =< 299 ->
+ case binary:split(Body, <<$\n>>, [global, trim]) of
+ [<<"http", _/binary>> = PutURL,
+ <<"http", _/binary>> = GetURL] ->
+ ?INFO_MSG("Got HTTP upload slot for ~s (file: ~s)",
+ [jlib:jid_to_string(JID), File]),
+ {ok, PutURL, GetURL};
+ Lines ->
+ ?ERROR_MSG("Can't parse data received for ~s from <~s>: ~p",
+ [jlib:jid_to_string(JID), ServiceURL, Lines]),
+ {error, ?ERR_SERVICE_UNAVAILABLE}
+ end;
+ {ok, {402, _Body}} ->
+ ?INFO_MSG("Got status code 402 for ~s from <~s>",
+ [jlib:jid_to_string(JID), ServiceURL]),
+ {error, ?ERR_RESOURCE_CONSTRAINT};
+ {ok, {403, _Body}} ->
+ ?INFO_MSG("Got status code 403 for ~s from <~s>",
+ [jlib:jid_to_string(JID), ServiceURL]),
+ {error, ?ERR_NOT_ALLOWED};
+ {ok, {413, _Body}} ->
+ ?INFO_MSG("Got status code 413 for ~s from <~s>",
+ [jlib:jid_to_string(JID), ServiceURL]),
+ {error, ?ERR_NOT_ACCEPTABLE};
+ {ok, {Code, _Body}} ->
+ ?ERROR_MSG("Got unexpected status code for ~s from <~s>: ~B",
+ [jlib:jid_to_string(JID), ServiceURL, Code]),
+ {error, ?ERR_SERVICE_UNAVAILABLE};
+ {error, Reason} ->
+ ?ERROR_MSG("Error requesting upload slot for ~s from <~s>: ~p",
+ [jlib:jid_to_string(JID), ServiceURL, Reason]),
+ {error, ?ERR_SERVICE_UNAVAILABLE}
end.
-spec add_slot(slot(), pos_integer(), timer:tref(), state()) -> state().
@@ -719,10 +769,10 @@ iq_disco_info(Lang, Name) ->
%% HTTP request handling.
--spec store_file(file:filename_all(), binary(),
+-spec store_file(binary(), binary(),
integer() | undefined,
integer() | undefined,
- binary(), binary(), boolean())
+ binary(), slot(), boolean())
-> ok | {ok, [{binary(), binary()}], binary()} | {error, term()}.
store_file(Path, Data, FileMode, DirMode, GetPrefix, LocalPath, Thumbnail) ->
@@ -731,10 +781,8 @@ store_file(Path, Data, FileMode, DirMode, GetPrefix, LocalPath, Thumbnail) ->
case identify(Path) of
{ok, MediaInfo} ->
case convert(Path, MediaInfo) of
- pass ->
- ok;
{ok, OutPath} ->
- [UserDir, RandDir|_] = LocalPath,
+ [UserDir, RandDir | _] = LocalPath,
FileName = filename:basename(OutPath),
URL = str:join([GetPrefix, UserDir,
RandDir, FileName], <<$/>>),
@@ -742,9 +790,11 @@ store_file(Path, Data, FileMode, DirMode, GetPrefix, LocalPath, Thumbnail) ->
{ok,
[{<<"Content-Type">>,
<<"text/xml; charset=utf-8">>}],
- xml:element_to_binary(ThumbEl)}
+ xml:element_to_binary(ThumbEl)};
+ pass ->
+ ok
end;
- {error, _} ->
+ pass ->
ok
end;
ok ->
@@ -779,10 +829,10 @@ do_store_file(Path, Data, FileMode, DirMode) ->
end,
ok = Ok % Raise an exception if file:write/2 failed.
catch
- _:{badmatch, {error, Error}} ->
- {error, ?FORMAT(Error)};
- _:Error ->
- {error, Error}
+ _:{badmatch, {error, Error}} ->
+ {error, Error};
+ _:Error ->
+ {error, Error}
end.
-spec guess_content_type(binary()) -> binary().
@@ -820,11 +870,11 @@ http_response(Host, Code, ExtraHeaders, Body) ->
end,
[]),
Headers = case proplists:is_defined(<<"Content-Type">>, ExtraHeaders) of
- true ->
- [ServerHeader | ExtraHeaders];
- false ->
- [ServerHeader, {<<"Content-Type">>, <<"text/plain">>} |
- ExtraHeaders]
+ true ->
+ [ServerHeader | ExtraHeaders];
+ false ->
+ [ServerHeader, {<<"Content-Type">>, <<"text/plain">>} |
+ ExtraHeaders]
end ++ CustomHeaders,
{Code, Headers, Body}.
@@ -839,56 +889,54 @@ code_to_message(500) -> <<"Internal server error.">>;
code_to_message(_Code) -> <<"">>.
%%--------------------------------------------------------------------
-%% Image manipulation stuff
+%% Image manipulation stuff.
%%--------------------------------------------------------------------
--spec identify(string()) -> {ok, media_info()} | {error, string()}.
+
+-spec identify(binary()) -> {ok, media_info()} | pass.
identify(Path) ->
- Cmd = lists:flatten(io_lib:fwrite("identify -format \"ok %m %h %w\" ~s",
- [Path])),
+ Cmd = io_lib:format("identify -format 'ok %m %h %w' ~s", [Path]),
Res = string:strip(os:cmd(Cmd), right, $\n),
case string:tokens(Res, " ") of
["ok", T, H, W] ->
- {ok, #media_info{
- type = string:to_lower(T),
- height = list_to_integer(H),
- width = list_to_integer(W)}};
+ {ok, #media_info{type = list_to_binary(string:to_lower(T)),
+ height = list_to_integer(H),
+ width = list_to_integer(W)}};
_ ->
- ?ERROR_MSG("failed to identify type of ~s: ~s", [Path, Res]),
- {error, Res}
+ ?DEBUG("Cannot identify type of ~s: ~s", [Path, Res]),
+ pass
end.
--spec convert(string(), media_info()) -> {ok, string()} | pass.
+-spec convert(binary(), media_info()) -> {ok, binary()} | pass.
convert(Path, #media_info{type = T, width = W, height = H}) ->
- if W*H >= 25000000 ->
- ?DEBUG("the image ~s is more than 25 Mbpx", [Path]),
+ if W * H >= 25000000 ->
+ ?DEBUG("The image ~s is more than 25 Mpix", [Path]),
pass;
- (W =< 300) and (H =< 300) ->
+ W =< 300, H =< 300 ->
{ok, Path};
- T == "gif"; T == "jpeg"; T == "png"; T == "webp" ->
+ T == <<"gif">>; T == <<"jpeg">>; T == <<"png">>; T == <<"webp">> ->
Dir = filename:dirname(Path),
- FileName = binary_to_list(randoms:get_string()) ++ "." ++ T,
+ FileName = <<(randoms:get_string())/binary, $., T/binary>>,
OutPath = filename:join(Dir, FileName),
- Cmd = lists:flatten(io_lib:fwrite("convert -resize 300 ~s ~s",
- [Path, OutPath])),
+ Cmd = io_lib:format("convert -resize 300 ~s ~s", [Path, OutPath]),
case os:cmd(Cmd) of
"" ->
{ok, OutPath};
Err ->
- ?ERROR_MSG("failed to convert ~s to ~s: ~s",
+ ?ERROR_MSG("Failed to convert ~s to ~s: ~s",
[Path, OutPath, string:strip(Err, right, $\n)]),
pass
end;
true ->
- ?DEBUG("do not call 'convert' for unknown type ~s", [T]),
+ ?DEBUG("Won't call 'convert' for unknown type ~s", [T]),
pass
end.
--spec thumb_el(string(), binary()) -> xmlel().
+-spec thumb_el(binary(), binary()) -> xmlel().
thumb_el(Path, URI) ->
- ContentType = guess_content_type(list_to_binary(Path)),
+ ContentType = guess_content_type(Path),
case identify(Path) of
{ok, #media_info{height = H, width = W}} ->
#xmlel{name = <<"thumbnail">>,
@@ -897,7 +945,7 @@ thumb_el(Path, URI) ->
{<<"uri">>, URI},
{<<"height">>, jlib:integer_to_binary(H)},
{<<"width">>, jlib:integer_to_binary(W)}]};
- {error, _} ->
+ pass ->
#xmlel{name = <<"thumbnail">>,
attrs = [{<<"xmlns">>, ?NS_THUMBS_1},
{<<"uri">>, URI},
@@ -929,7 +977,7 @@ remove_user(User, Server) ->
?DEBUG("Found no HTTP upload directory of ~s@~s", [User, Server]);
{error, Error} ->
?ERROR_MSG("Cannot remove HTTP upload directory of ~s@~s: ~p",
- [User, Server, Error])
+ [User, Server, ?FORMAT(Error)])
end,
ok.
@@ -942,16 +990,16 @@ del_tree(Dir) ->
{ok, Entries} = file:list_dir(Dir),
lists:foreach(fun(Path) ->
case filelib:is_dir(Path) of
- true ->
- ok = del_tree(Path);
- false ->
- ok = file:delete(Path)
+ true ->
+ ok = del_tree(Path);
+ false ->
+ ok = file:delete(Path)
end
end, [Dir ++ "/" ++ Entry || Entry <- Entries]),
ok = file:del_dir(Dir)
catch
- _:{badmatch, {error, Error}} ->
- {error, ?FORMAT(Error)};
- _:Error ->
- {error, Error}
+ _:{badmatch, {error, Error}} ->
+ {error, Error};
+ _:Error ->
+ {error, Error}
end.
diff --git a/src/mod_http_upload_quota.erl b/src/mod_http_upload_quota.erl
index 1b7828a5..d7576567 100644
--- a/src/mod_http_upload_quota.erl
+++ b/src/mod_http_upload_quota.erl
@@ -1,9 +1,27 @@
-%%%-------------------------------------------------------------------
+%%%----------------------------------------------------------------------
%%% File : mod_http_upload_quota.erl
%%% Author : Holger Weiss <holger@zedat.fu-berlin.de>
%%% Purpose : Quota management for HTTP File Upload (XEP-0363)
%%% Created : 15 Oct 2015 by Holger Weiss <holger@zedat.fu-berlin.de>
-%%%-------------------------------------------------------------------
+%%%
+%%%
+%%% ejabberd, Copyright (C) 2015 ProcessOne
+%%%
+%%% This program is free software; you can redistribute it and/or
+%%% modify it under the terms of the GNU General Public License as
+%%% published by the Free Software Foundation; either version 2 of the
+%%% License, or (at your option) any later version.
+%%%
+%%% This program is distributed in the hope that it will be useful,
+%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+%%% General Public License for more details.
+%%%
+%%% You should have received a copy of the GNU General Public License along
+%%% with this program; if not, write to the Free Software Foundation, Inc.,
+%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+%%%
+%%%----------------------------------------------------------------------
-module(mod_http_upload_quota).
-author('holger@zedat.fu-berlin.de').
@@ -75,8 +93,8 @@ start(ServerHost, Opts) ->
stop(ServerHost) ->
Proc = mod_http_upload:get_proc_name(ServerHost, ?PROCNAME),
- ok = supervisor:terminate_child(ejabberd_sup, Proc),
- ok = supervisor:delete_child(ejabberd_sup, Proc).
+ supervisor:terminate_child(ejabberd_sup, Proc),
+ supervisor:delete_child(ejabberd_sup, Proc).
-spec mod_opt_type(atom()) -> fun((term()) -> term()) | [atom()].
@@ -143,47 +161,52 @@ handle_cast({handle_slot_request, #jid{user = U, server = S} = JID, Path, Size},
access_hard_quota = AccessHardQuota,
disk_usage = DiskUsage} = State) ->
HardQuota = case acl:match_rule(ServerHost, AccessHardQuota, JID) of
- Hard when is_integer(Hard), Hard > 0 ->
- Hard * 1024 * 1024;
- _ ->
- 0
+ Hard when is_integer(Hard), Hard > 0 ->
+ Hard * 1024 * 1024;
+ _ ->
+ 0
end,
SoftQuota = case acl:match_rule(ServerHost, AccessSoftQuota, JID) of
- Soft when is_integer(Soft), Soft > 0 ->
- Soft * 1024 * 1024;
- _ ->
- 0
+ Soft when is_integer(Soft), Soft > 0 ->
+ Soft * 1024 * 1024;
+ _ ->
+ 0
end,
OldSize = case dict:find({U, S}, DiskUsage) of
- {ok, Value} ->
- Value;
- error ->
- undefined
+ {ok, Value} ->
+ Value;
+ error ->
+ undefined
end,
NewSize = case {HardQuota, SoftQuota} of
- {0, 0} ->
- ?DEBUG("No quota specified for ~s",
- [jlib:jid_to_string(JID)]),
- Size;
- {0, _} ->
+ {0, 0} ->
+ ?DEBUG("No quota specified for ~s",
+ [jlib:jid_to_string(JID)]),
+ undefined;
+ {0, _} ->
?WARNING_MSG("No hard quota specified for ~s",
[jlib:jid_to_string(JID)]),
enforce_quota(Path, Size, OldSize, SoftQuota, SoftQuota);
- {_, 0} ->
+ {_, 0} ->
?WARNING_MSG("No soft quota specified for ~s",
[jlib:jid_to_string(JID)]),
enforce_quota(Path, Size, OldSize, HardQuota, HardQuota);
- _ when SoftQuota > HardQuota ->
+ _ when SoftQuota > HardQuota ->
?WARNING_MSG("Bad quota for ~s (soft: ~p, hard: ~p)",
[jlib:jid_to_string(JID),
SoftQuota, HardQuota]),
enforce_quota(Path, Size, OldSize, SoftQuota, SoftQuota);
- _ ->
+ _ ->
?DEBUG("Enforcing quota for ~s",
[jlib:jid_to_string(JID)]),
enforce_quota(Path, Size, OldSize, SoftQuota, HardQuota)
end,
- {noreply, State#state{disk_usage = dict:store({U, S}, NewSize, DiskUsage)}};
+ NewDiskUsage = if is_integer(NewSize) ->
+ dict:store({U, S}, NewSize, DiskUsage);
+ true ->
+ DiskUsage
+ end,
+ {noreply, State#state{disk_usage = NewDiskUsage}};
handle_cast(Request, State) ->
?ERROR_MSG("Got unexpected request: ~p", [Request]),
{noreply, State}.
@@ -196,17 +219,19 @@ handle_info(sweep, #state{server_host = ServerHost,
when is_integer(MaxDays), MaxDays > 0 ->
?DEBUG("Got 'sweep' message for ~s", [ServerHost]),
case file:list_dir(DocRoot) of
- {ok, Entries} ->
- BackThen = secs_since_epoch() - (MaxDays * 86400),
- DocRootS = binary_to_list(DocRoot),
- PathNames = lists:map(fun(Entry) -> DocRootS ++ "/" ++ Entry end,
- Entries),
- UserDirs = lists:filter(fun filelib:is_dir/1, PathNames),
- lists:foreach(fun(UserDir) -> delete_old_files(UserDir, BackThen) end,
- UserDirs);
- {error, Error} ->
- ?ERROR_MSG("Cannot open document root ~s: ~s",
- [DocRoot, ?FORMAT(Error)])
+ {ok, Entries} ->
+ BackThen = secs_since_epoch() - (MaxDays * 86400),
+ DocRootS = binary_to_list(DocRoot),
+ PathNames = lists:map(fun(Entry) ->
+ DocRootS ++ "/" ++ Entry
+ end, Entries),
+ UserDirs = lists:filter(fun filelib:is_dir/1, PathNames),
+ lists:foreach(fun(UserDir) ->
+ delete_old_files(UserDir, BackThen)
+ end, UserDirs);
+ {error, Error} ->
+ ?ERROR_MSG("Cannot open document root ~s: ~s",
+ [DocRoot, ?FORMAT(Error)])
end,
{noreply, State};
handle_info(Info, State) ->
@@ -276,14 +301,14 @@ enforce_quota(UserDir, SlotSize, _OldSize, MinSize, MaxSize) ->
-spec delete_old_files(file:filename_all(), integer()) -> ok.
-delete_old_files(UserDir, Timestamp) ->
+delete_old_files(UserDir, CutOff) ->
FileInfo = gather_file_info(UserDir),
- case [Path || {Path, _Size, Time} <- FileInfo, Time < Timestamp] of
- [] ->
- ok;
- OldFiles ->
- lists:foreach(fun(File) -> del_file_and_dir(File) end, OldFiles),
- file:del_dir(UserDir) % In case it's empty, now.
+ case [Path || {Path, _Size, Time} <- FileInfo, Time < CutOff] of
+ [] ->
+ ok;
+ OldFiles ->
+ lists:foreach(fun(File) -> del_file_and_dir(File) end, OldFiles),
+ file:del_dir(UserDir) % In case it's empty, now.
end.
-spec gather_file_info(file:filename_all())
@@ -293,49 +318,50 @@ gather_file_info(Dir) when is_binary(Dir) ->
gather_file_info(binary_to_list(Dir));
gather_file_info(Dir) ->
case file:list_dir(Dir) of
- {ok, Entries} ->
- lists:foldl(fun(Entry, Acc) ->
- Path = Dir ++ "/" ++ Entry,
- case file:read_file_info(Path, [{time, posix}]) of
- {ok, #file_info{type = directory}} ->
- gather_file_info(Path) ++ Acc;
- {ok, #file_info{type = regular,
- mtime = Time,
- size = Size}} ->
- [{Path, Size, Time} | Acc];
- {ok, _Info} ->
- ?DEBUG("Won't stat(2) non-regular file ~s",
- [Path]),
- Acc;
- {error, Error} ->
- ?ERROR_MSG("Cannot stat(2) ~s: ~s",
- [Path, ?FORMAT(Error)]),
- Acc
- end
- end, [], Entries);
- {error, enoent} ->
- ?DEBUG("Directory ~s doesn't exist", [Dir]),
- [];
- {error, Error} ->
- ?ERROR_MSG("Cannot open directory ~s: ~s", [Dir, ?FORMAT(Error)]),
- []
+ {ok, Entries} ->
+ lists:foldl(fun(Entry, Acc) ->
+ Path = Dir ++ "/" ++ Entry,
+ case file:read_file_info(Path,
+ [{time, posix}]) of
+ {ok, #file_info{type = directory}} ->
+ gather_file_info(Path) ++ Acc;
+ {ok, #file_info{type = regular,
+ mtime = Time,
+ size = Size}} ->
+ [{Path, Size, Time} | Acc];
+ {ok, _Info} ->
+ ?DEBUG("Won't stat(2) non-regular file ~s",
+ [Path]),
+ Acc;
+ {error, Error} ->
+ ?ERROR_MSG("Cannot stat(2) ~s: ~s",
+ [Path, ?FORMAT(Error)]),
+ Acc
+ end
+ end, [], Entries);
+ {error, enoent} ->
+ ?DEBUG("Directory ~s doesn't exist", [Dir]),
+ [];
+ {error, Error} ->
+ ?ERROR_MSG("Cannot open directory ~s: ~s", [Dir, ?FORMAT(Error)]),
+ []
end.
-spec del_file_and_dir(file:name_all()) -> ok.
del_file_and_dir(File) ->
case file:delete(File) of
- ok ->
- ?INFO_MSG("Removed ~s", [File]),
- Dir = filename:dirname(File),
- case file:del_dir(Dir) of
- ok ->
- ?DEBUG("Removed ~s", [Dir]);
- {error, Error} ->
- ?INFO_MSG("Cannot remove ~s: ~s", [Dir, ?FORMAT(Error)])
- end;
- {error, Error} ->
- ?WARNING_MSG("Cannot remove ~s: ~s", [File, ?FORMAT(Error)])
+ ok ->
+ ?INFO_MSG("Removed ~s", [File]),
+ Dir = filename:dirname(File),
+ case file:del_dir(Dir) of
+ ok ->
+ ?DEBUG("Removed ~s", [Dir]);
+ {error, Error} ->
+ ?DEBUG("Cannot remove ~s: ~s", [Dir, ?FORMAT(Error)])
+ end;
+ {error, Error} ->
+ ?WARNING_MSG("Cannot remove ~s: ~s", [File, ?FORMAT(Error)])
end.
-spec secs_since_epoch() -> non_neg_integer().
diff --git a/src/mod_mam.erl b/src/mod_mam.erl
index 7781cff9..c23e695d 100644
--- a/src/mod_mam.erl
+++ b/src/mod_mam.erl
@@ -25,7 +25,7 @@
%%%-------------------------------------------------------------------
-module(mod_mam).
--protocol({xep, 313, '0.3'}).
+-protocol({xep, 313, '0.4'}).
-behaviour(gen_mod).
diff --git a/src/mod_muc.erl b/src/mod_muc.erl
index 05148f8e..890687cd 100644
--- a/src/mod_muc.erl
+++ b/src/mod_muc.erl
@@ -91,7 +91,6 @@ start_link(Host, Opts) ->
[Host, Opts], []).
start(Host, Opts) ->
- start_supervisor(Host),
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
ChildSpec = {Proc, {?MODULE, start_link, [Host, Opts]},
temporary, 1000, worker, [?MODULE]},
@@ -99,7 +98,6 @@ start(Host, Opts) ->
stop(Host) ->
Rooms = shutdown_rooms(Host),
- stop_supervisor(Host),
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
gen_server:call(Proc, stop),
supervisor:delete_child(ejabberd_sup, Proc),
@@ -444,19 +442,6 @@ code_change(_OldVsn, State, _Extra) -> {ok, State}.
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-start_supervisor(Host) ->
- Proc = gen_mod:get_module_proc(Host,
- ejabberd_mod_muc_sup),
- ChildSpec = {Proc,
- {ejabberd_tmp_sup, start_link, [Proc, mod_muc_room]},
- permanent, infinity, supervisor, [ejabberd_tmp_sup]},
- supervisor:start_child(ejabberd_sup, ChildSpec).
-
-stop_supervisor(Host) ->
- Proc = gen_mod:get_module_proc(Host,
- ejabberd_mod_muc_sup),
- supervisor:terminate_child(ejabberd_sup, Proc),
- supervisor:delete_child(ejabberd_sup, Proc).
do_route(Host, ServerHost, Access, HistorySize, RoomShaper,
From, To, Packet, DefRoomOpts) ->
diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl
index cf26bdea..0572bca2 100644
--- a/src/mod_muc_room.erl
+++ b/src/mod_muc_room.erl
@@ -70,32 +70,19 @@
-endif.
-%% Module start with or without supervisor:
--ifdef(NO_TRANSIENT_SUPERVISORS).
--define(SUPERVISOR_START,
- gen_fsm:start(?MODULE, [Host, ServerHost, Access, Room, HistorySize,
- RoomShaper, Creator, Nick, DefRoomOpts],
- ?FSMOPTS)).
--else.
--define(SUPERVISOR_START,
- Supervisor = gen_mod:get_module_proc(ServerHost, ejabberd_mod_muc_sup),
- supervisor:start_child(
- Supervisor, [Host, ServerHost, Access, Room, HistorySize, RoomShaper,
- Creator, Nick, DefRoomOpts])).
--endif.
-
%%%----------------------------------------------------------------------
%%% API
%%%----------------------------------------------------------------------
start(Host, ServerHost, Access, Room, HistorySize, RoomShaper,
Creator, Nick, DefRoomOpts) ->
- ?SUPERVISOR_START.
+ gen_fsm:start(?MODULE, [Host, ServerHost, Access, Room, HistorySize,
+ RoomShaper, Creator, Nick, DefRoomOpts],
+ ?FSMOPTS).
start(Host, ServerHost, Access, Room, HistorySize, RoomShaper, Opts) ->
- Supervisor = gen_mod:get_module_proc(ServerHost, ejabberd_mod_muc_sup),
- supervisor:start_child(
- Supervisor, [Host, ServerHost, Access, Room, HistorySize, RoomShaper,
- Opts]).
+ gen_fsm:start(?MODULE, [Host, ServerHost, Access, Room, HistorySize,
+ RoomShaper, Opts],
+ ?FSMOPTS).
start_link(Host, ServerHost, Access, Room, HistorySize, RoomShaper,
Creator, Nick, DefRoomOpts) ->
@@ -376,7 +363,8 @@ normal_state({route, From, <<"">>,
catch
send_new_presence(TargetJid,
Reason,
- NSD),
+ NSD,
+ StateData),
NSD;
_ -> StateData
end
@@ -1044,7 +1032,7 @@ process_presence(From, Nick,
StateData),
case (?DICT):find(Nick, StateData#state.nicks) of
{ok, [_, _ | _]} -> ok;
- _ -> send_new_presence(From, NewState)
+ _ -> send_new_presence(From, NewState, StateData)
end,
Reason = case xml:get_subtag(NewPacket,
<<"status">>)
@@ -1122,7 +1110,8 @@ process_presence(From, Nick,
end,
NewState = add_user_presence(From, Stanza,
StateData),
- send_new_presence(From, NewState),
+ send_new_presence(
+ From, NewState, StateData),
NewState
end
end
@@ -1328,7 +1317,7 @@ expulse_participant(Packet, From, StateData, Reason1) ->
[{xmlcdata,
Reason2}]}]},
StateData),
- send_new_presence(From, NewState),
+ send_new_presence(From, NewState, StateData),
remove_online_user(From, NewState).
set_affiliation(JID, Affiliation, StateData) ->
@@ -1852,7 +1841,7 @@ add_new_user(From, Nick,
add_online_user(From, Nick, Role,
StateData)),
send_existing_presences(From, NewState),
- send_new_presence(From, NewState),
+ send_new_presence(From, NewState, StateData),
Shift = count_stanza_shift(Nick, Els, NewState),
case send_history(From, Shift, NewState) of
true -> ok;
@@ -2083,6 +2072,10 @@ is_room_overcrowded(StateData) ->
?DEFAULT_MAX_USERS_PRESENCE),
(?DICT):size(StateData#state.users) > MaxUsersPresence.
+presence_broadcast_allowed(JID, StateData) ->
+ Role = get_role(JID, StateData),
+ lists:member(Role, (StateData#state.config)#config.presence_broadcast).
+
send_update_presence(JID, StateData) ->
send_update_presence(JID, <<"">>, StateData).
@@ -2110,15 +2103,17 @@ send_update_presence1(JID, Reason, StateData) ->
end
end,
lists:foreach(fun (J) ->
- send_new_presence(J, Reason, StateData)
+ send_new_presence(J, Reason, StateData, StateData)
end,
LJIDs).
-send_new_presence(NJID, StateData) ->
- send_new_presence(NJID, <<"">>, StateData).
+send_new_presence(NJID, StateData, OldStateData) ->
+ send_new_presence(NJID, <<"">>, StateData, OldStateData).
-send_new_presence(NJID, Reason, StateData) ->
- case is_room_overcrowded(StateData) of
+send_new_presence(NJID, Reason, StateData, OldStateData) ->
+ case is_room_overcrowded(StateData) orelse
+ not (presence_broadcast_allowed(NJID, StateData) orelse
+ presence_broadcast_allowed(NJID, OldStateData)) of
true -> ok;
false -> send_new_presence1(NJID, Reason, StateData)
end.
@@ -2302,8 +2297,12 @@ change_nick(JID, Nick, StateData) ->
end,
NewStateData = StateData#state{users = Users,
nicks = Nicks},
- send_nick_changing(JID, OldNick, NewStateData,
- SendOldUnavailable, SendNewAvailable),
+ case presence_broadcast_allowed(JID, NewStateData) of
+ true ->
+ send_nick_changing(JID, OldNick, NewStateData,
+ SendOldUnavailable, SendNewAvailable);
+ false -> ok
+ end,
add_to_log(nickchange, {OldNick, Nick}, StateData),
NewStateData.
@@ -2679,7 +2678,7 @@ process_item_change(E, SD, UJID) ->
{JID, role, Role, Reason} ->
SD1 = set_role(JID, Role, SD),
catch
- send_new_presence(JID, Reason, SD1),
+ send_new_presence(JID, Reason, SD1, SD),
SD1;
{JID, affiliation, A, _Reason} ->
SD1 = set_affiliation(JID, A, SD),
@@ -3419,6 +3418,53 @@ get_config(Lang, StateData, From) ->
children =
[{xmlcdata,
<<"anyone">>}]}]}]},
+ #xmlel{name = <<"field">>,
+ attrs =
+ [{<<"type">>, <<"list-multi">>},
+ {<<"label">>,
+ translate:translate(Lang,
+ <<"Roles for which Presence is Broadcasted">>)},
+ {<<"var">>, <<"muc#roomconfig_presencebroadcast">>}],
+ children =
+ lists:map(
+ fun(Role) ->
+ #xmlel{name = <<"value">>, attrs = [],
+ children =
+ [{xmlcdata,
+ atom_to_binary(Role, utf8)}]}
+ end, Config#config.presence_broadcast
+ ) ++
+ [#xmlel{name = <<"option">>,
+ attrs =
+ [{<<"label">>,
+ translate:translate(Lang,
+ <<"Moderator">>)}],
+ children =
+ [#xmlel{name = <<"value">>, attrs = [],
+ children =
+ [{xmlcdata,
+ <<"moderator">>}]}]},
+ #xmlel{name = <<"option">>,
+ attrs =
+ [{<<"label">>,
+ translate:translate(Lang,
+ <<"Participant">>)}],
+ children =
+ [#xmlel{name = <<"value">>, attrs = [],
+ children =
+ [{xmlcdata,
+ <<"participant">>}]}]},
+ #xmlel{name = <<"option">>,
+ attrs =
+ [{<<"label">>,
+ translate:translate(Lang,
+ <<"Visitor">>)}],
+ children =
+ [#xmlel{name = <<"value">>, attrs = [],
+ children =
+ [{xmlcdata,
+ <<"visitor">>}]}]}
+ ]},
?BOOLXFIELD(<<"Make room members-only">>,
<<"muc#roomconfig_membersonly">>,
(Config#config.members_only)),
@@ -3692,6 +3738,28 @@ set_xoption([{<<"muc#roomconfig_roomsecret">>, [Val]}
set_xoption([{<<"anonymous">>, [Val]} | Opts],
Config) ->
?SET_BOOL_XOPT(anonymous, Val);
+set_xoption([{<<"muc#roomconfig_presencebroadcast">>, Vals} | Opts],
+ Config) ->
+ Roles =
+ lists:foldl(
+ fun(_S, error) -> error;
+ (S, {M, P, V}) ->
+ case S of
+ <<"moderator">> -> {true, P, V};
+ <<"participant">> -> {M, true, V};
+ <<"visitor">> -> {M, P, true};
+ _ -> error
+ end
+ end, {false, false, false}, Vals),
+ case Roles of
+ error -> {error, ?ERR_BAD_REQUEST};
+ {M, P, V} ->
+ Res =
+ if M -> [moderator]; true -> [] end ++
+ if P -> [participant]; true -> [] end ++
+ if V -> [visitor]; true -> [] end,
+ set_xoption(Opts, Config#config{presence_broadcast = Res})
+ end;
set_xoption([{<<"muc#roomconfig_allowvoicerequests">>,
[Val]}
| Opts],
@@ -3885,6 +3953,10 @@ set_opts([{Opt, Val} | Opts], StateData) ->
StateData#state{config =
(StateData#state.config)#config{anonymous =
Val}};
+ presence_broadcast ->
+ StateData#state{config =
+ (StateData#state.config)#config{presence_broadcast =
+ Val}};
logging ->
StateData#state{config =
(StateData#state.config)#config{logging =
diff --git a/src/mod_ping.erl b/src/mod_ping.erl
index 9964daf0..54aa6086 100644
--- a/src/mod_ping.erl
+++ b/src/mod_ping.erl
@@ -255,6 +255,8 @@ cancel_timer(TRef) ->
mod_opt_type(iqdisc) -> fun gen_iq_handler:check_type/1;
mod_opt_type(ping_interval) ->
fun (I) when is_integer(I), I > 0 -> I end;
+mod_opt_type(ping_ack_timeout) ->
+ fun (I) when is_integer(I), I > 0 -> I end;
mod_opt_type(send_pings) ->
fun (B) when is_boolean(B) -> B end;
mod_opt_type(timeout_action) ->
@@ -262,4 +264,4 @@ mod_opt_type(timeout_action) ->
(kill) -> kill
end;
mod_opt_type(_) ->
- [iqdisc, ping_interval, send_pings, timeout_action].
+ [iqdisc, ping_interval, ping_ack_timeout, send_pings, timeout_action].
diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl
index 306bd844..ed6bff11 100644
--- a/src/mod_vcard.erl
+++ b/src/mod_vcard.erl
@@ -94,7 +94,7 @@ start(Host, Opts) ->
<<"vjud.@HOST@">>),
Search = gen_mod:get_opt(search, Opts,
fun(B) when is_boolean(B) -> B end,
- true),
+ false),
register(gen_mod:get_module_proc(Host, ?PROCNAME),
spawn(?MODULE, init, [MyHost, Host, Search])).
diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl
index f75bb071..3f6b41a7 100644
--- a/src/mod_vcard_ldap.erl
+++ b/src/mod_vcard_ldap.erl
@@ -55,7 +55,7 @@
{serverhost = <<"">> :: binary(),
myhost = <<"">> :: binary(),
eldap_id = <<"">> :: binary(),
- search = true :: boolean(),
+ search = false :: boolean(),
servers = [] :: [binary()],
backups = [] :: [binary()],
port = ?LDAP_PORT :: inet:port_number(),
@@ -735,7 +735,7 @@ parse_options(Host, Opts) ->
<<"vjud.@HOST@">>),
Search = gen_mod:get_opt(search, Opts,
fun(B) when is_boolean(B) -> B end,
- true),
+ false),
Matches = gen_mod:get_opt(matches, Opts,
fun(infinity) -> 0;
(I) when is_integer(I), I>0 -> I
diff --git a/vars.config.in b/vars.config.in
index 69cc516f..5c37fb97 100644
--- a/vars.config.in
+++ b/vars.config.in
@@ -8,7 +8,6 @@
%%%-------------------------------------------------------------------
%% Macros
{roster_gateway_workaround, @roster_gateway_workaround@}.
-{transient_supervisors, @transient_supervisors@}.
{full_xml, @full_xml@}.
{nif, @nif@}.
{db_type, @db_type@}.