mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-22 16:20:52 +01:00
* src/aclocal.m4: Updated for zlib support
* src/configure.ac: Likewise * src/mod_muc/mod_muc_room.erl: Weakened presence filtering, added warning in non-anonymous rooms, room destroying updated to latest JEP-0045, added a number of occupants and room name in room's disco#info reply, miscellaneous internal changes (thanks to Sergei Golovan) * src/mod_muc/mod_muc.erl: Better support for nick unregistration (thanks to Sergei Golovan) * src/ejabberd_zlib/ejabberd_zlib.erl: Zlib support (thanks to Sergei Golovan) * src/ejabberd_zlib/ejabberd_zlib_drv.c: Likewise * src/ejabberd_zlib/Makefile.in: Likewise * src/ejabberd_c2s.erl: Stream compression support (JEP-0138) * src/ejabberd_receiver.erl: Likewise * src/mod_disco.erl: Don't split node name before calling hooks (thanks to Sergei Golovan) * src/mod_configure.erl: Support for configuration using ad-hoc commands (thanks to Sergei Golovan) * src/mod_announce.erl: Support for sending announce messages using ad-hoc commands (thanks to Sergei Golovan) * src/mod_adhoc.erl: Ad-hoc support (JEP-0050) (thanks to Magnus Henoch) * src/adhoc.erl: Likewise * src/adhoc.hrl: Likewise * src/jlib.hrl: Updated (thanks to Sergei Golovan) * src/gen_mod.erl: Added function is_loaded/2 (thanks to Sergei Golovan) * src/ejabberd_service.erl: Changed error message on handshake error (thanks to Sergei Golovan) * src/ejabberd.cfg.example: Updated (thanks to Sergei Golovan) SVN Revision: 486
This commit is contained in:
parent
c7bafe0056
commit
568909d5bb
47
ChangeLog
47
ChangeLog
@ -1,4 +1,49 @@
|
|||||||
2006-01-13 Mickaël Rémond <mickael.remond@process-one.net>
|
2006-01-19 Alexey Shchepin <alexey@sevcom.net>
|
||||||
|
|
||||||
|
* src/aclocal.m4: Updated for zlib support
|
||||||
|
* src/configure.ac: Likewise
|
||||||
|
|
||||||
|
* src/mod_muc/mod_muc_room.erl: Weakened presence filtering, added
|
||||||
|
warning in non-anonymous rooms, room destroying updated to latest
|
||||||
|
JEP-0045, added a number of occupants and room name in room's
|
||||||
|
disco#info reply, miscellaneous internal changes (thanks to Sergei
|
||||||
|
Golovan)
|
||||||
|
|
||||||
|
* src/mod_muc/mod_muc.erl: Better support for nick unregistration
|
||||||
|
(thanks to Sergei Golovan)
|
||||||
|
|
||||||
|
* src/ejabberd_zlib/ejabberd_zlib.erl: Zlib support (thanks to
|
||||||
|
Sergei Golovan)
|
||||||
|
* src/ejabberd_zlib/ejabberd_zlib_drv.c: Likewise
|
||||||
|
* src/ejabberd_zlib/Makefile.in: Likewise
|
||||||
|
* src/ejabberd_c2s.erl: Stream compression support (JEP-0138)
|
||||||
|
* src/ejabberd_receiver.erl: Likewise
|
||||||
|
|
||||||
|
* src/mod_disco.erl: Don't split node name before calling hooks
|
||||||
|
(thanks to Sergei Golovan)
|
||||||
|
|
||||||
|
* src/mod_configure.erl: Support for configuration using ad-hoc
|
||||||
|
commands (thanks to Sergei Golovan)
|
||||||
|
|
||||||
|
* src/mod_announce.erl: Support for sending announce messages
|
||||||
|
using ad-hoc commands (thanks to Sergei Golovan)
|
||||||
|
|
||||||
|
* src/mod_adhoc.erl: Ad-hoc support (JEP-0050) (thanks to Magnus
|
||||||
|
Henoch)
|
||||||
|
* src/adhoc.erl: Likewise
|
||||||
|
* src/adhoc.hrl: Likewise
|
||||||
|
|
||||||
|
* src/jlib.hrl: Updated (thanks to Sergei Golovan)
|
||||||
|
|
||||||
|
* src/gen_mod.erl: Added function is_loaded/2 (thanks to Sergei
|
||||||
|
Golovan)
|
||||||
|
|
||||||
|
* src/ejabberd_service.erl: Changed error message on handshake
|
||||||
|
error (thanks to Sergei Golovan)
|
||||||
|
|
||||||
|
* src/ejabberd.cfg.example: Updated (thanks to Sergei Golovan)
|
||||||
|
|
||||||
|
2006-01-13 Mickael Remond <mickael.remond@process-one.net>
|
||||||
|
|
||||||
* src/odbc/ejabberd_odbc.erl: underscore and percent are now only
|
* src/odbc/ejabberd_odbc.erl: underscore and percent are now only
|
||||||
escaped in like queries. MySQL where not escaping those escaped
|
escaped in like queries. MySQL where not escaping those escaped
|
||||||
|
@ -23,7 +23,7 @@ endif
|
|||||||
|
|
||||||
prefix = @prefix@
|
prefix = @prefix@
|
||||||
|
|
||||||
SUBDIRS = @mod_irc@ @mod_pubsub@ @mod_muc@ @eldap@ @web@ stringprep @tls@ @odbc@
|
SUBDIRS = @mod_irc@ @mod_pubsub@ @mod_muc@ @eldap@ @web@ stringprep @tls@ @odbc@ @ejabberd_zlib@
|
||||||
ERLSHLIBS = expat_erl.so
|
ERLSHLIBS = expat_erl.so
|
||||||
SOURCES = $(wildcard *.erl)
|
SOURCES = $(wildcard *.erl)
|
||||||
BEAMS = $(SOURCES:.erl=.beam)
|
BEAMS = $(SOURCES:.erl=.beam)
|
||||||
|
31
src/aclocal.m4
vendored
31
src/aclocal.m4
vendored
@ -29,6 +29,37 @@ AC_DEFUN(AM_WITH_EXPAT,
|
|||||||
AC_SUBST(EXPAT_LIBS)
|
AC_SUBST(EXPAT_LIBS)
|
||||||
])
|
])
|
||||||
|
|
||||||
|
AC_DEFUN(AM_WITH_ZLIB,
|
||||||
|
[ AC_ARG_WITH(zlib,
|
||||||
|
[ --with-zlib=PREFIX prefix where zlib is installed])
|
||||||
|
|
||||||
|
ZLIB_CFLAGS=
|
||||||
|
ZLIB_LIBS=
|
||||||
|
if test x"$with_zlib" != x; then
|
||||||
|
ZLIB_CFLAGS="-I$with_zlib/include"
|
||||||
|
ZLIB_LIBS="-L$with_zlib/lib"
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_CHECK_LIB(z, gzgets,
|
||||||
|
[ ZLIB_LIBS="$ZLIB_LIBS -lz"
|
||||||
|
zlib_found=yes ],
|
||||||
|
[ zlib_found=no ],
|
||||||
|
"$ZLIB_LIBS")
|
||||||
|
if test $zlib_found = no; then
|
||||||
|
AC_MSG_ERROR([Could not find the zlib library])
|
||||||
|
fi
|
||||||
|
zlib_save_CFLAGS="$CFLAGS"
|
||||||
|
CFLAGS="$CFLAGS $ZLIB_CFLAGS"
|
||||||
|
AC_CHECK_HEADERS(zlib.h, , zlib_found=no)
|
||||||
|
if test $zlib_found = no; then
|
||||||
|
AC_MSG_ERROR([Could not find zlib.h])
|
||||||
|
fi
|
||||||
|
CFLAGS="$zlib_save_CFLAGS"
|
||||||
|
|
||||||
|
AC_SUBST(ZLIB_CFLAGS)
|
||||||
|
AC_SUBST(ZLIB_LIBS)
|
||||||
|
])
|
||||||
|
|
||||||
AC_DEFUN(AM_WITH_ERLANG,
|
AC_DEFUN(AM_WITH_ERLANG,
|
||||||
[ AC_ARG_WITH(erlang,
|
[ AC_ARG_WITH(erlang,
|
||||||
[ --with-erlang=PREFIX path to erlc and erl ])
|
[ --with-erlang=PREFIX path to erlc and erl ])
|
||||||
|
111
src/adhoc.erl
Normal file
111
src/adhoc.erl
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
%%% File : adhoc.erl
|
||||||
|
%%% Author : Magnus Henoch <henoch@dtek.chalmers.se>
|
||||||
|
%%% Purpose : Provide helper functions for ad-hoc commands (JEP-0050)
|
||||||
|
%%% Created : 31 Oct 2005 by Magnus Henoch <henoch@dtek.chalmers.se>
|
||||||
|
%%% Id : $Id$
|
||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
|
-module(adhoc).
|
||||||
|
-author('henoch@dtek.chalmers.se').
|
||||||
|
-vsn('$Revision$ ').
|
||||||
|
|
||||||
|
-export([parse_request/1,
|
||||||
|
produce_response/2,
|
||||||
|
produce_response/1]).
|
||||||
|
|
||||||
|
-include("ejabberd.hrl").
|
||||||
|
-include("jlib.hrl").
|
||||||
|
-include("adhoc.hrl").
|
||||||
|
|
||||||
|
%% Parse an ad-hoc request. Return either an adhoc_request record or
|
||||||
|
%% an {error, ErrorType} tuple.
|
||||||
|
parse_request(#iq{type = set, lang = Lang, sub_el = SubEl, xmlns = ?NS_COMMANDS}) ->
|
||||||
|
?DEBUG("entering parse_request...", []),
|
||||||
|
Node = xml:get_tag_attr_s("node", SubEl),
|
||||||
|
SessionID = xml:get_tag_attr_s("sessionid", SubEl),
|
||||||
|
Action = xml:get_tag_attr_s("action", SubEl),
|
||||||
|
XData = find_xdata_el(SubEl),
|
||||||
|
{xmlelement, _, _, AllEls} = SubEl,
|
||||||
|
if XData ->
|
||||||
|
Others = lists:delete(XData, AllEls);
|
||||||
|
true ->
|
||||||
|
Others = AllEls
|
||||||
|
end,
|
||||||
|
|
||||||
|
#adhoc_request{lang = Lang,
|
||||||
|
node = Node,
|
||||||
|
sessionid = SessionID,
|
||||||
|
action = Action,
|
||||||
|
xdata = XData,
|
||||||
|
others = Others};
|
||||||
|
parse_request(_) ->
|
||||||
|
{error, ?ERR_BAD_REQUEST}.
|
||||||
|
|
||||||
|
%% Borrowed from mod_vcard.erl
|
||||||
|
find_xdata_el({xmlelement, _Name, _Attrs, SubEls}) ->
|
||||||
|
find_xdata_el1(SubEls).
|
||||||
|
|
||||||
|
find_xdata_el1([]) ->
|
||||||
|
false;
|
||||||
|
find_xdata_el1([{xmlelement, Name, Attrs, SubEls} | Els]) ->
|
||||||
|
case xml:get_attr_s("xmlns", Attrs) of
|
||||||
|
?NS_XDATA ->
|
||||||
|
{xmlelement, Name, Attrs, SubEls};
|
||||||
|
_ ->
|
||||||
|
find_xdata_el1(Els)
|
||||||
|
end;
|
||||||
|
find_xdata_el1([_ | Els]) ->
|
||||||
|
find_xdata_el1(Els).
|
||||||
|
|
||||||
|
%% Produce a <command/> node to use as response from an adhoc_response
|
||||||
|
%% record, filling in values for language, node and session id from
|
||||||
|
%% the request.
|
||||||
|
produce_response(#adhoc_request{lang = Lang,
|
||||||
|
node = Node,
|
||||||
|
sessionid = SessionID},
|
||||||
|
Response) ->
|
||||||
|
produce_response(Response#adhoc_response{lang = Lang,
|
||||||
|
node = Node,
|
||||||
|
sessionid = SessionID}).
|
||||||
|
|
||||||
|
%% Produce a <command/> node to use as response from an adhoc_response
|
||||||
|
%% record.
|
||||||
|
produce_response(#adhoc_response{lang = _Lang,
|
||||||
|
node = Node,
|
||||||
|
sessionid = ProvidedSessionID,
|
||||||
|
status = Status,
|
||||||
|
defaultaction = DefaultAction,
|
||||||
|
actions = Actions,
|
||||||
|
notes = Notes,
|
||||||
|
elements = Elements}) ->
|
||||||
|
SessionID = if is_list(ProvidedSessionID), ProvidedSessionID /= "" ->
|
||||||
|
ProvidedSessionID;
|
||||||
|
true ->
|
||||||
|
jlib:now_to_utc_string(now())
|
||||||
|
end,
|
||||||
|
case Actions of
|
||||||
|
[] ->
|
||||||
|
ActionsEls = [];
|
||||||
|
_ ->
|
||||||
|
case DefaultAction of
|
||||||
|
"" ->
|
||||||
|
ActionsElAttrs = [];
|
||||||
|
_ ->
|
||||||
|
ActionsElAttrs = [{"execute", DefaultAction}]
|
||||||
|
end,
|
||||||
|
ActionsEls = [{xmlelement, "actions",
|
||||||
|
ActionsElAttrs,
|
||||||
|
[{xmlelement, Action, [], []} || Action <- Actions]}]
|
||||||
|
end,
|
||||||
|
NotesEls = lists:map(fun({Type, Text}) ->
|
||||||
|
{xmlelement, "note",
|
||||||
|
[{"type", Type}],
|
||||||
|
[{xmlcdata, Text}]}
|
||||||
|
end, Notes),
|
||||||
|
{xmlelement, "command",
|
||||||
|
[{"xmlns", ?NS_COMMANDS},
|
||||||
|
{"sessionid", SessionID},
|
||||||
|
{"node", Node},
|
||||||
|
{"status", atom_to_list(Status)}],
|
||||||
|
ActionsEls ++ NotesEls ++ Elements}.
|
15
src/adhoc.hrl
Normal file
15
src/adhoc.hrl
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
-record(adhoc_request, {lang,
|
||||||
|
node,
|
||||||
|
sessionid,
|
||||||
|
action,
|
||||||
|
xdata,
|
||||||
|
others}).
|
||||||
|
|
||||||
|
-record(adhoc_response, {lang,
|
||||||
|
node,
|
||||||
|
sessionid,
|
||||||
|
status,
|
||||||
|
defaultaction = "",
|
||||||
|
actions = [],
|
||||||
|
notes = [],
|
||||||
|
elements = []}).
|
286
src/configure
vendored
286
src/configure
vendored
@ -310,7 +310,7 @@ ac_includes_default="\
|
|||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
#endif"
|
#endif"
|
||||||
|
|
||||||
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT SET_MAKE ERLC ac_pt_ERLC ERL ac_pt_ERL ERLANG_CFLAGS ERLANG_LIBS LIBICONV CPP EGREP EXPAT_CFLAGS EXPAT_LIBS LIBOBJS mod_pubsub make_mod_pubsub mod_irc make_mod_irc mod_muc make_mod_muc eldap make_eldap web make_web tls make_tls odbc make_odbc roster_gateway_workaround SSL_LIBS SSL_CFLAGS LTLIBOBJS'
|
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT SET_MAKE ERLC ac_pt_ERLC ERL ac_pt_ERL ERLANG_CFLAGS ERLANG_LIBS LIBICONV CPP EGREP EXPAT_CFLAGS EXPAT_LIBS ZLIB_CFLAGS ZLIB_LIBS LIBOBJS mod_pubsub make_mod_pubsub mod_irc make_mod_irc mod_muc make_mod_muc eldap make_eldap web make_web tls make_tls odbc make_odbc ejabberd_zlib make_ejabberd_zlib roster_gateway_workaround SSL_LIBS SSL_CFLAGS LTLIBOBJS'
|
||||||
ac_subst_files=''
|
ac_subst_files=''
|
||||||
|
|
||||||
# Initialize some variables set by options.
|
# Initialize some variables set by options.
|
||||||
@ -850,6 +850,7 @@ Optional Features:
|
|||||||
--enable-web enable web (default: yes)
|
--enable-web enable web (default: yes)
|
||||||
--enable-tls enable tls (default: yes)
|
--enable-tls enable tls (default: yes)
|
||||||
--enable-odbc enable odbc (default: no)
|
--enable-odbc enable odbc (default: no)
|
||||||
|
--enable-ejabberd_zlib enable ejabberd_zlib (default: yes)
|
||||||
--enable-roster-gateway-workaround Turn on workaround for processing gateway subscriptions
|
--enable-roster-gateway-workaround Turn on workaround for processing gateway subscriptions
|
||||||
|
|
||||||
Optional Packages:
|
Optional Packages:
|
||||||
@ -858,6 +859,7 @@ Optional Packages:
|
|||||||
--with-erlang=PREFIX path to erlc and erl
|
--with-erlang=PREFIX path to erlc and erl
|
||||||
--with-libiconv-prefix=PREFIX prefix where libiconv is installed
|
--with-libiconv-prefix=PREFIX prefix where libiconv is installed
|
||||||
--with-expat=PREFIX prefix where EXPAT is installed
|
--with-expat=PREFIX prefix where EXPAT is installed
|
||||||
|
--with-zlib=PREFIX prefix where zlib is installed
|
||||||
--with-openssl=PREFIX prefix where OPENSSL is installed
|
--with-openssl=PREFIX prefix where OPENSSL is installed
|
||||||
|
|
||||||
Some influential environment variables:
|
Some influential environment variables:
|
||||||
@ -3563,6 +3565,259 @@ echo "$as_me: error: Could not find expat.h" >&2;}
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#locating zlib
|
||||||
|
|
||||||
|
# Check whether --with-zlib or --without-zlib was given.
|
||||||
|
if test "${with_zlib+set}" = set; then
|
||||||
|
withval="$with_zlib"
|
||||||
|
|
||||||
|
fi;
|
||||||
|
|
||||||
|
ZLIB_CFLAGS=
|
||||||
|
ZLIB_LIBS=
|
||||||
|
if test x"$with_zlib" != x; then
|
||||||
|
ZLIB_CFLAGS="-I$with_zlib/include"
|
||||||
|
ZLIB_LIBS="-L$with_zlib/lib"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$as_me:$LINENO: checking for gzgets in -lz" >&5
|
||||||
|
echo $ECHO_N "checking for gzgets in -lz... $ECHO_C" >&6
|
||||||
|
if test "${ac_cv_lib_z_gzgets+set}" = set; then
|
||||||
|
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||||
|
else
|
||||||
|
ac_check_lib_save_LIBS=$LIBS
|
||||||
|
LIBS="-lz "$ZLIB_LIBS" $LIBS"
|
||||||
|
cat >conftest.$ac_ext <<_ACEOF
|
||||||
|
/* confdefs.h. */
|
||||||
|
_ACEOF
|
||||||
|
cat confdefs.h >>conftest.$ac_ext
|
||||||
|
cat >>conftest.$ac_ext <<_ACEOF
|
||||||
|
/* end confdefs.h. */
|
||||||
|
|
||||||
|
/* Override any gcc2 internal prototype to avoid an error. */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
#endif
|
||||||
|
/* We use char because int might match the return type of a gcc2
|
||||||
|
builtin and then its argument prototype would still apply. */
|
||||||
|
char gzgets ();
|
||||||
|
int
|
||||||
|
main ()
|
||||||
|
{
|
||||||
|
gzgets ();
|
||||||
|
;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_ACEOF
|
||||||
|
rm -f conftest.$ac_objext conftest$ac_exeext
|
||||||
|
if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
|
||||||
|
(eval $ac_link) 2>conftest.er1
|
||||||
|
ac_status=$?
|
||||||
|
grep -v '^ *+' conftest.er1 >conftest.err
|
||||||
|
rm -f conftest.er1
|
||||||
|
cat conftest.err >&5
|
||||||
|
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||||
|
(exit $ac_status); } &&
|
||||||
|
{ ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
|
||||||
|
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
|
||||||
|
(eval $ac_try) 2>&5
|
||||||
|
ac_status=$?
|
||||||
|
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||||
|
(exit $ac_status); }; } &&
|
||||||
|
{ ac_try='test -s conftest$ac_exeext'
|
||||||
|
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
|
||||||
|
(eval $ac_try) 2>&5
|
||||||
|
ac_status=$?
|
||||||
|
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||||
|
(exit $ac_status); }; }; then
|
||||||
|
ac_cv_lib_z_gzgets=yes
|
||||||
|
else
|
||||||
|
echo "$as_me: failed program was:" >&5
|
||||||
|
sed 's/^/| /' conftest.$ac_ext >&5
|
||||||
|
|
||||||
|
ac_cv_lib_z_gzgets=no
|
||||||
|
fi
|
||||||
|
rm -f conftest.err conftest.$ac_objext \
|
||||||
|
conftest$ac_exeext conftest.$ac_ext
|
||||||
|
LIBS=$ac_check_lib_save_LIBS
|
||||||
|
fi
|
||||||
|
echo "$as_me:$LINENO: result: $ac_cv_lib_z_gzgets" >&5
|
||||||
|
echo "${ECHO_T}$ac_cv_lib_z_gzgets" >&6
|
||||||
|
if test $ac_cv_lib_z_gzgets = yes; then
|
||||||
|
ZLIB_LIBS="$ZLIB_LIBS -lz"
|
||||||
|
zlib_found=yes
|
||||||
|
else
|
||||||
|
zlib_found=no
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test $zlib_found = no; then
|
||||||
|
{ { echo "$as_me:$LINENO: error: Could not find the zlib library" >&5
|
||||||
|
echo "$as_me: error: Could not find the zlib library" >&2;}
|
||||||
|
{ (exit 1); exit 1; }; }
|
||||||
|
fi
|
||||||
|
zlib_save_CFLAGS="$CFLAGS"
|
||||||
|
CFLAGS="$CFLAGS $ZLIB_CFLAGS"
|
||||||
|
|
||||||
|
for ac_header in zlib.h
|
||||||
|
do
|
||||||
|
as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
||||||
|
if eval "test \"\${$as_ac_Header+set}\" = set"; then
|
||||||
|
echo "$as_me:$LINENO: checking for $ac_header" >&5
|
||||||
|
echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
|
||||||
|
if eval "test \"\${$as_ac_Header+set}\" = set"; then
|
||||||
|
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||||
|
fi
|
||||||
|
echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
|
||||||
|
echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
|
||||||
|
else
|
||||||
|
# Is the header compilable?
|
||||||
|
echo "$as_me:$LINENO: checking $ac_header usability" >&5
|
||||||
|
echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
|
||||||
|
cat >conftest.$ac_ext <<_ACEOF
|
||||||
|
/* confdefs.h. */
|
||||||
|
_ACEOF
|
||||||
|
cat confdefs.h >>conftest.$ac_ext
|
||||||
|
cat >>conftest.$ac_ext <<_ACEOF
|
||||||
|
/* end confdefs.h. */
|
||||||
|
$ac_includes_default
|
||||||
|
#include <$ac_header>
|
||||||
|
_ACEOF
|
||||||
|
rm -f conftest.$ac_objext
|
||||||
|
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
|
||||||
|
(eval $ac_compile) 2>conftest.er1
|
||||||
|
ac_status=$?
|
||||||
|
grep -v '^ *+' conftest.er1 >conftest.err
|
||||||
|
rm -f conftest.er1
|
||||||
|
cat conftest.err >&5
|
||||||
|
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||||
|
(exit $ac_status); } &&
|
||||||
|
{ ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
|
||||||
|
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
|
||||||
|
(eval $ac_try) 2>&5
|
||||||
|
ac_status=$?
|
||||||
|
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||||
|
(exit $ac_status); }; } &&
|
||||||
|
{ ac_try='test -s conftest.$ac_objext'
|
||||||
|
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
|
||||||
|
(eval $ac_try) 2>&5
|
||||||
|
ac_status=$?
|
||||||
|
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||||
|
(exit $ac_status); }; }; then
|
||||||
|
ac_header_compiler=yes
|
||||||
|
else
|
||||||
|
echo "$as_me: failed program was:" >&5
|
||||||
|
sed 's/^/| /' conftest.$ac_ext >&5
|
||||||
|
|
||||||
|
ac_header_compiler=no
|
||||||
|
fi
|
||||||
|
rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||||
|
echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
|
||||||
|
echo "${ECHO_T}$ac_header_compiler" >&6
|
||||||
|
|
||||||
|
# Is the header present?
|
||||||
|
echo "$as_me:$LINENO: checking $ac_header presence" >&5
|
||||||
|
echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
|
||||||
|
cat >conftest.$ac_ext <<_ACEOF
|
||||||
|
/* confdefs.h. */
|
||||||
|
_ACEOF
|
||||||
|
cat confdefs.h >>conftest.$ac_ext
|
||||||
|
cat >>conftest.$ac_ext <<_ACEOF
|
||||||
|
/* end confdefs.h. */
|
||||||
|
#include <$ac_header>
|
||||||
|
_ACEOF
|
||||||
|
if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
|
||||||
|
(eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
|
||||||
|
ac_status=$?
|
||||||
|
grep -v '^ *+' conftest.er1 >conftest.err
|
||||||
|
rm -f conftest.er1
|
||||||
|
cat conftest.err >&5
|
||||||
|
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||||
|
(exit $ac_status); } >/dev/null; then
|
||||||
|
if test -s conftest.err; then
|
||||||
|
ac_cpp_err=$ac_c_preproc_warn_flag
|
||||||
|
ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
|
||||||
|
else
|
||||||
|
ac_cpp_err=
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
ac_cpp_err=yes
|
||||||
|
fi
|
||||||
|
if test -z "$ac_cpp_err"; then
|
||||||
|
ac_header_preproc=yes
|
||||||
|
else
|
||||||
|
echo "$as_me: failed program was:" >&5
|
||||||
|
sed 's/^/| /' conftest.$ac_ext >&5
|
||||||
|
|
||||||
|
ac_header_preproc=no
|
||||||
|
fi
|
||||||
|
rm -f conftest.err conftest.$ac_ext
|
||||||
|
echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
|
||||||
|
echo "${ECHO_T}$ac_header_preproc" >&6
|
||||||
|
|
||||||
|
# So? What about this header?
|
||||||
|
case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
|
||||||
|
yes:no: )
|
||||||
|
{ echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
|
||||||
|
echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
|
||||||
|
{ echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
|
||||||
|
echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
|
||||||
|
ac_header_preproc=yes
|
||||||
|
;;
|
||||||
|
no:yes:* )
|
||||||
|
{ echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
|
||||||
|
echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
|
||||||
|
{ echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
|
||||||
|
echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
|
||||||
|
{ echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
|
||||||
|
echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
|
||||||
|
{ echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
|
||||||
|
echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
|
||||||
|
{ echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
|
||||||
|
echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
|
||||||
|
{ echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
|
||||||
|
echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
|
||||||
|
(
|
||||||
|
cat <<\_ASBOX
|
||||||
|
## --------------------------------- ##
|
||||||
|
## Report this to BUG-REPORT-ADDRESS ##
|
||||||
|
## --------------------------------- ##
|
||||||
|
_ASBOX
|
||||||
|
) |
|
||||||
|
sed "s/^/$as_me: WARNING: /" >&2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
echo "$as_me:$LINENO: checking for $ac_header" >&5
|
||||||
|
echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
|
||||||
|
if eval "test \"\${$as_ac_Header+set}\" = set"; then
|
||||||
|
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||||
|
else
|
||||||
|
eval "$as_ac_Header=\$ac_header_preproc"
|
||||||
|
fi
|
||||||
|
echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
|
||||||
|
echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
|
||||||
|
|
||||||
|
fi
|
||||||
|
if test `eval echo '${'$as_ac_Header'}'` = yes; then
|
||||||
|
cat >>confdefs.h <<_ACEOF
|
||||||
|
#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
|
||||||
|
_ACEOF
|
||||||
|
|
||||||
|
else
|
||||||
|
zlib_found=no
|
||||||
|
fi
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
if test $zlib_found = no; then
|
||||||
|
{ { echo "$as_me:$LINENO: error: Could not find zlib.h" >&5
|
||||||
|
echo "$as_me: error: Could not find zlib.h" >&2;}
|
||||||
|
{ (exit 1); exit 1; }; }
|
||||||
|
fi
|
||||||
|
CFLAGS="$zlib_save_CFLAGS"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Checks for typedefs, structures, and compiler characteristics.
|
# Checks for typedefs, structures, and compiler characteristics.
|
||||||
echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5
|
echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5
|
||||||
@ -4224,6 +4479,28 @@ echo "${ECHO_T}$mr_enable_odbc" >&6
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ejabberd_zlib=
|
||||||
|
make_ejabberd_zlib=
|
||||||
|
echo "$as_me:$LINENO: checking whether build ejabberd_zlib" >&5
|
||||||
|
echo $ECHO_N "checking whether build ejabberd_zlib... $ECHO_C" >&6
|
||||||
|
# Check whether --enable-ejabberd_zlib or --disable-ejabberd_zlib was given.
|
||||||
|
if test "${enable_ejabberd_zlib+set}" = set; then
|
||||||
|
enableval="$enable_ejabberd_zlib"
|
||||||
|
mr_enable_ejabberd_zlib="$enableval"
|
||||||
|
else
|
||||||
|
mr_enable_ejabberd_zlib=yes
|
||||||
|
fi;
|
||||||
|
if test "$mr_enable_ejabberd_zlib" = "yes"; then
|
||||||
|
ejabberd_zlib=ejabberd_zlib
|
||||||
|
make_ejabberd_zlib=ejabberd_zlib/Makefile
|
||||||
|
fi
|
||||||
|
echo "$as_me:$LINENO: result: $mr_enable_ejabberd_zlib" >&5
|
||||||
|
echo "${ECHO_T}$mr_enable_ejabberd_zlib" >&6
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Check whether --enable-roster_gateway_workaround or --disable-roster_gateway_workaround was given.
|
# Check whether --enable-roster_gateway_workaround or --disable-roster_gateway_workaround was given.
|
||||||
if test "${enable_roster_gateway_workaround+set}" = set; then
|
if test "${enable_roster_gateway_workaround+set}" = set; then
|
||||||
enableval="$enable_roster_gateway_workaround"
|
enableval="$enable_roster_gateway_workaround"
|
||||||
@ -4239,7 +4516,7 @@ else
|
|||||||
fi;
|
fi;
|
||||||
|
|
||||||
|
|
||||||
ac_config_files="$ac_config_files Makefile $make_mod_irc $make_mod_muc $make_mod_pubsub $make_eldap $make_web stringprep/Makefile $make_tls $make_odbc"
|
ac_config_files="$ac_config_files Makefile $make_mod_irc $make_mod_muc $make_mod_pubsub $make_eldap $make_web stringprep/Makefile $make_tls $make_odbc $make_ejabberd_zlib"
|
||||||
|
|
||||||
#openssl
|
#openssl
|
||||||
|
|
||||||
@ -5056,6 +5333,7 @@ do
|
|||||||
"stringprep/Makefile" ) CONFIG_FILES="$CONFIG_FILES stringprep/Makefile" ;;
|
"stringprep/Makefile" ) CONFIG_FILES="$CONFIG_FILES stringprep/Makefile" ;;
|
||||||
"$make_tls" ) CONFIG_FILES="$CONFIG_FILES $make_tls" ;;
|
"$make_tls" ) CONFIG_FILES="$CONFIG_FILES $make_tls" ;;
|
||||||
"$make_odbc" ) CONFIG_FILES="$CONFIG_FILES $make_odbc" ;;
|
"$make_odbc" ) CONFIG_FILES="$CONFIG_FILES $make_odbc" ;;
|
||||||
|
"$make_ejabberd_zlib" ) CONFIG_FILES="$CONFIG_FILES $make_ejabberd_zlib" ;;
|
||||||
*) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
|
*) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
|
||||||
echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
|
echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
|
||||||
{ (exit 1); exit 1; }; };;
|
{ (exit 1); exit 1; }; };;
|
||||||
@ -5158,6 +5436,8 @@ s,@CPP@,$CPP,;t t
|
|||||||
s,@EGREP@,$EGREP,;t t
|
s,@EGREP@,$EGREP,;t t
|
||||||
s,@EXPAT_CFLAGS@,$EXPAT_CFLAGS,;t t
|
s,@EXPAT_CFLAGS@,$EXPAT_CFLAGS,;t t
|
||||||
s,@EXPAT_LIBS@,$EXPAT_LIBS,;t t
|
s,@EXPAT_LIBS@,$EXPAT_LIBS,;t t
|
||||||
|
s,@ZLIB_CFLAGS@,$ZLIB_CFLAGS,;t t
|
||||||
|
s,@ZLIB_LIBS@,$ZLIB_LIBS,;t t
|
||||||
s,@LIBOBJS@,$LIBOBJS,;t t
|
s,@LIBOBJS@,$LIBOBJS,;t t
|
||||||
s,@mod_pubsub@,$mod_pubsub,;t t
|
s,@mod_pubsub@,$mod_pubsub,;t t
|
||||||
s,@make_mod_pubsub@,$make_mod_pubsub,;t t
|
s,@make_mod_pubsub@,$make_mod_pubsub,;t t
|
||||||
@ -5173,6 +5453,8 @@ s,@tls@,$tls,;t t
|
|||||||
s,@make_tls@,$make_tls,;t t
|
s,@make_tls@,$make_tls,;t t
|
||||||
s,@odbc@,$odbc,;t t
|
s,@odbc@,$odbc,;t t
|
||||||
s,@make_odbc@,$make_odbc,;t t
|
s,@make_odbc@,$make_odbc,;t t
|
||||||
|
s,@ejabberd_zlib@,$ejabberd_zlib,;t t
|
||||||
|
s,@make_ejabberd_zlib@,$make_ejabberd_zlib,;t t
|
||||||
s,@roster_gateway_workaround@,$roster_gateway_workaround,;t t
|
s,@roster_gateway_workaround@,$roster_gateway_workaround,;t t
|
||||||
s,@SSL_LIBS@,$SSL_LIBS,;t t
|
s,@SSL_LIBS@,$SSL_LIBS,;t t
|
||||||
s,@SSL_CFLAGS@,$SSL_CFLAGS,;t t
|
s,@SSL_CFLAGS@,$SSL_CFLAGS,;t t
|
||||||
|
@ -14,6 +14,8 @@ AM_WITH_ERLANG
|
|||||||
AM_ICONV
|
AM_ICONV
|
||||||
#locating libexpat
|
#locating libexpat
|
||||||
AM_WITH_EXPAT
|
AM_WITH_EXPAT
|
||||||
|
#locating zlib
|
||||||
|
AM_WITH_ZLIB
|
||||||
|
|
||||||
# Checks for typedefs, structures, and compiler characteristics.
|
# Checks for typedefs, structures, and compiler characteristics.
|
||||||
AC_C_CONST
|
AC_C_CONST
|
||||||
@ -29,6 +31,7 @@ AC_MOD_ENABLE(eldap, yes)
|
|||||||
AC_MOD_ENABLE(web, yes)
|
AC_MOD_ENABLE(web, yes)
|
||||||
AC_MOD_ENABLE(tls, yes)
|
AC_MOD_ENABLE(tls, yes)
|
||||||
AC_MOD_ENABLE(odbc, no)
|
AC_MOD_ENABLE(odbc, no)
|
||||||
|
AC_MOD_ENABLE(ejabberd_zlib, yes)
|
||||||
|
|
||||||
AC_ARG_ENABLE(roster_gateway_workaround,
|
AC_ARG_ENABLE(roster_gateway_workaround,
|
||||||
[ --enable-roster-gateway-workaround Turn on workaround for processing gateway subscriptions],
|
[ --enable-roster-gateway-workaround Turn on workaround for processing gateway subscriptions],
|
||||||
@ -47,7 +50,8 @@ AC_CONFIG_FILES([Makefile
|
|||||||
$make_web
|
$make_web
|
||||||
stringprep/Makefile
|
stringprep/Makefile
|
||||||
$make_tls
|
$make_tls
|
||||||
$make_odbc])
|
$make_odbc
|
||||||
|
$make_ejabberd_zlib])
|
||||||
#openssl
|
#openssl
|
||||||
AM_WITH_OPENSSL
|
AM_WITH_OPENSSL
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
@ -134,13 +134,14 @@
|
|||||||
{mod_register, [{access, register}]},
|
{mod_register, [{access, register}]},
|
||||||
{mod_roster, []},
|
{mod_roster, []},
|
||||||
{mod_privacy, []},
|
{mod_privacy, []},
|
||||||
{mod_configure, []},
|
{mod_adhoc, []},
|
||||||
|
{mod_configure, []}, % Depends on mod_adhoc
|
||||||
{mod_configure2, []},
|
{mod_configure2, []},
|
||||||
{mod_disco, []},
|
{mod_disco, []},
|
||||||
{mod_stats, []},
|
{mod_stats, []},
|
||||||
{mod_vcard, []},
|
{mod_vcard, []},
|
||||||
{mod_offline, []},
|
{mod_offline, []},
|
||||||
{mod_announce, [{access, announce}]},
|
{mod_announce, [{access, announce}]}, % Depends on mod_adhoc
|
||||||
{mod_echo, [{host, "echo.localhost"}]},
|
{mod_echo, [{host, "echo.localhost"}]},
|
||||||
{mod_private, []},
|
{mod_private, []},
|
||||||
{mod_irc, []},
|
{mod_irc, []},
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
sasl_state,
|
sasl_state,
|
||||||
access,
|
access,
|
||||||
shaper,
|
shaper,
|
||||||
|
zlib = false,
|
||||||
tls = false,
|
tls = false,
|
||||||
tls_required = false,
|
tls_required = false,
|
||||||
tls_enabled = false,
|
tls_enabled = false,
|
||||||
@ -125,6 +126,7 @@ init([{SockMod, Socket}, Opts]) ->
|
|||||||
{value, {_, S}} -> S;
|
{value, {_, S}} -> S;
|
||||||
_ -> none
|
_ -> none
|
||||||
end,
|
end,
|
||||||
|
Zlib = lists:member(zlib, Opts),
|
||||||
StartTLS = lists:member(starttls, Opts),
|
StartTLS = lists:member(starttls, Opts),
|
||||||
StartTLSRequired = lists:member(starttls_required, Opts),
|
StartTLSRequired = lists:member(starttls_required, Opts),
|
||||||
TLSEnabled = lists:member(tls, Opts),
|
TLSEnabled = lists:member(tls, Opts),
|
||||||
@ -145,6 +147,7 @@ init([{SockMod, Socket}, Opts]) ->
|
|||||||
{ok, wait_for_stream, #state{socket = Socket1,
|
{ok, wait_for_stream, #state{socket = Socket1,
|
||||||
sockmod = SockMod1,
|
sockmod = SockMod1,
|
||||||
receiver = ReceiverPid,
|
receiver = ReceiverPid,
|
||||||
|
zlib = Zlib,
|
||||||
tls = TLS,
|
tls = TLS,
|
||||||
tls_required = StartTLSRequired,
|
tls_required = StartTLSRequired,
|
||||||
tls_enabled = TLSEnabled,
|
tls_enabled = TLSEnabled,
|
||||||
@ -200,10 +203,22 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
|||||||
{xmlelement, "mechanism", [],
|
{xmlelement, "mechanism", [],
|
||||||
[{xmlcdata, S}]}
|
[{xmlcdata, S}]}
|
||||||
end, cyrsasl:listmech(Server)),
|
end, cyrsasl:listmech(Server)),
|
||||||
|
SockMod = StateData#state.sockmod,
|
||||||
|
Zlib = StateData#state.zlib,
|
||||||
|
CompressFeature =
|
||||||
|
case Zlib andalso
|
||||||
|
(SockMod /= ejabberd_zlib) of
|
||||||
|
true ->
|
||||||
|
[{xmlelement, "compression",
|
||||||
|
[{"xmlns", ?NS_FEATURE_COMPRESS}],
|
||||||
|
[{xmlelement, "method",
|
||||||
|
[], [{xmlcdata, "zlib"}]}]}];
|
||||||
|
_ ->
|
||||||
|
[]
|
||||||
|
end,
|
||||||
TLS = StateData#state.tls,
|
TLS = StateData#state.tls,
|
||||||
TLSEnabled = StateData#state.tls_enabled,
|
TLSEnabled = StateData#state.tls_enabled,
|
||||||
TLSRequired = StateData#state.tls_required,
|
TLSRequired = StateData#state.tls_required,
|
||||||
SockMod = StateData#state.sockmod,
|
|
||||||
TLSFeature =
|
TLSFeature =
|
||||||
case (TLS == true) andalso
|
case (TLS == true) andalso
|
||||||
(TLSEnabled == false) andalso
|
(TLSEnabled == false) andalso
|
||||||
@ -224,7 +239,7 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
|||||||
end,
|
end,
|
||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
{xmlelement, "stream:features", [],
|
{xmlelement, "stream:features", [],
|
||||||
TLSFeature ++
|
TLSFeature ++ CompressFeature ++
|
||||||
[{xmlelement, "mechanisms",
|
[{xmlelement, "mechanisms",
|
||||||
[{"xmlns", ?NS_SASL}],
|
[{"xmlns", ?NS_SASL}],
|
||||||
Mechs}] ++
|
Mechs}] ++
|
||||||
@ -337,7 +352,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
|
|||||||
end,
|
end,
|
||||||
send_element(StateData, Res),
|
send_element(StateData, Res),
|
||||||
{next_state, wait_for_auth, StateData};
|
{next_state, wait_for_auth, StateData};
|
||||||
{auth, _ID, set, {U, P, D, ""}} ->
|
{auth, _ID, set, {_U, _P, _D, ""}} ->
|
||||||
Err = jlib:make_error_reply(
|
Err = jlib:make_error_reply(
|
||||||
El,
|
El,
|
||||||
?ERR_AUTH_NO_RESOURCE_PROVIDED(StateData#state.lang)),
|
?ERR_AUTH_NO_RESOURCE_PROVIDED(StateData#state.lang)),
|
||||||
@ -434,6 +449,7 @@ wait_for_auth(closed, StateData) ->
|
|||||||
|
|
||||||
wait_for_feature_request({xmlstreamelement, El}, StateData) ->
|
wait_for_feature_request({xmlstreamelement, El}, StateData) ->
|
||||||
{xmlelement, Name, Attrs, Els} = El,
|
{xmlelement, Name, Attrs, Els} = El,
|
||||||
|
Zlib = StateData#state.zlib,
|
||||||
TLS = StateData#state.tls,
|
TLS = StateData#state.tls,
|
||||||
TLSEnabled = StateData#state.tls_enabled,
|
TLSEnabled = StateData#state.tls_enabled,
|
||||||
TLSRequired = StateData#state.tls_required,
|
TLSRequired = StateData#state.tls_required,
|
||||||
@ -497,6 +513,19 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) ->
|
|||||||
streamid = new_id(),
|
streamid = new_id(),
|
||||||
tls_enabled = true
|
tls_enabled = true
|
||||||
}};
|
}};
|
||||||
|
{?NS_COMPRESS, "compress"} when Zlib == true,
|
||||||
|
SockMod /= ejabberd_zlib ->
|
||||||
|
Socket = StateData#state.socket,
|
||||||
|
{ok, ZlibSocket} = ejabberd_zlib:enable_zlib(SockMod, Socket),
|
||||||
|
ejabberd_receiver:compress(StateData#state.receiver, ZlibSocket),
|
||||||
|
send_element(StateData,
|
||||||
|
{xmlelement, "compressed",
|
||||||
|
[{"xmlns", ?NS_COMPRESS}], []}),
|
||||||
|
{next_state, wait_for_stream,
|
||||||
|
StateData#state{sockmod = ejabberd_zlib,
|
||||||
|
socket = ZlibSocket,
|
||||||
|
streamid = new_id()
|
||||||
|
}};
|
||||||
_ ->
|
_ ->
|
||||||
if
|
if
|
||||||
(SockMod == gen_tcp) and TLSRequired ->
|
(SockMod == gen_tcp) and TLSRequired ->
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
change_shaper/2,
|
change_shaper/2,
|
||||||
reset_stream/1,
|
reset_stream/1,
|
||||||
starttls/2,
|
starttls/2,
|
||||||
|
compress/2,
|
||||||
become_controller/1,
|
become_controller/1,
|
||||||
close/1]).
|
close/1]).
|
||||||
|
|
||||||
@ -54,6 +55,9 @@ reset_stream(Pid) ->
|
|||||||
starttls(Pid, TLSSocket) ->
|
starttls(Pid, TLSSocket) ->
|
||||||
gen_server:call(Pid, {starttls, TLSSocket}).
|
gen_server:call(Pid, {starttls, TLSSocket}).
|
||||||
|
|
||||||
|
compress(Pid, ZlibSocket) ->
|
||||||
|
gen_server:call(Pid, {compress, ZlibSocket}).
|
||||||
|
|
||||||
become_controller(Pid) ->
|
become_controller(Pid) ->
|
||||||
gen_server:call(Pid, become_controller).
|
gen_server:call(Pid, become_controller).
|
||||||
|
|
||||||
@ -110,6 +114,20 @@ handle_call({starttls, TLSSocket}, _From,
|
|||||||
{error, _Reason} ->
|
{error, _Reason} ->
|
||||||
{stop, normal, ok, NewState}
|
{stop, normal, ok, NewState}
|
||||||
end;
|
end;
|
||||||
|
handle_call({compress, ZlibSocket}, _From,
|
||||||
|
#state{xml_stream_state = XMLStreamState,
|
||||||
|
c2s_pid = C2SPid} = State) ->
|
||||||
|
xml_stream:close(XMLStreamState),
|
||||||
|
NewXMLStreamState = xml_stream:new(C2SPid),
|
||||||
|
NewState = State#state{socket = ZlibSocket,
|
||||||
|
sock_mod = ejabberd_zlib,
|
||||||
|
xml_stream_state = NewXMLStreamState},
|
||||||
|
case ejabberd_zlib:recv_data(ZlibSocket, "") of
|
||||||
|
{ok, ZlibData} ->
|
||||||
|
{reply, ok, process_data(ZlibData, NewState)};
|
||||||
|
{error, _Reason} ->
|
||||||
|
{stop, normal, ok, NewState}
|
||||||
|
end;
|
||||||
handle_call(reset_stream, _From,
|
handle_call(reset_stream, _From,
|
||||||
#state{xml_stream_state = XMLStreamState,
|
#state{xml_stream_state = XMLStreamState,
|
||||||
c2s_pid = C2SPid} = State) ->
|
c2s_pid = C2SPid} = State) ->
|
||||||
@ -157,6 +175,13 @@ handle_info({Tag, _TCPSocket, Data},
|
|||||||
{error, _Reason} ->
|
{error, _Reason} ->
|
||||||
{stop, normal, State}
|
{stop, normal, State}
|
||||||
end;
|
end;
|
||||||
|
ejabberd_zlib ->
|
||||||
|
case ejabberd_zlib:recv_data(Socket, Data) of
|
||||||
|
{ok, ZlibData} ->
|
||||||
|
{noreply, process_data(ZlibData, State)};
|
||||||
|
{error, _Reason} ->
|
||||||
|
{stop, normal, State}
|
||||||
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
{noreply, process_data(Data, State)}
|
{noreply, process_data(Data, State)}
|
||||||
end;
|
end;
|
||||||
@ -211,7 +236,6 @@ activate_socket(#state{socket = Socket,
|
|||||||
SockMod:setopts(Socket, [{active, once}])
|
SockMod:setopts(Socket, [{active, once}])
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
process_data(Data,
|
process_data(Data,
|
||||||
#state{xml_stream_state = XMLStreamState,
|
#state{xml_stream_state = XMLStreamState,
|
||||||
shaper_state = ShaperState} = State) ->
|
shaper_state = ShaperState} = State) ->
|
||||||
|
@ -179,7 +179,7 @@ wait_for_handshake({xmlstreamelement, El}, StateData) ->
|
|||||||
end, StateData#state.hosts),
|
end, StateData#state.hosts),
|
||||||
{next_state, stream_established, StateData};
|
{next_state, stream_established, StateData};
|
||||||
_ ->
|
_ ->
|
||||||
send_text(StateData, ?INVALID_HEADER_ERR),
|
send_text(StateData, ?INVALID_HANDSHAKE_ERR),
|
||||||
{stop, normal, StateData}
|
{stop, normal, StateData}
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
|
38
src/ejabberd_zlib/Makefile.in
Normal file
38
src/ejabberd_zlib/Makefile.in
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# $Id$
|
||||||
|
|
||||||
|
CC = @CC@
|
||||||
|
CFLAGS = @CFLAGS@ @ZLIB_CFLAGS@ @ERLANG_CFLAGS@
|
||||||
|
CPPFLAGS = @CPPFLAGS@
|
||||||
|
LDFLAGS = @LDFLAGS@
|
||||||
|
LIBS = @LIBS@ @ZLIB_LIBS@ @ERLANG_LIBS@
|
||||||
|
|
||||||
|
SUBDIRS =
|
||||||
|
|
||||||
|
ERLSHLIBS = ../ejabberd_zlib_drv.so
|
||||||
|
|
||||||
|
OUTDIR = ..
|
||||||
|
EFLAGS = -I .. -pz ..
|
||||||
|
OBJS = \
|
||||||
|
$(OUTDIR)/ejabberd_zlib.beam
|
||||||
|
|
||||||
|
all: $(OBJS) $(ERLSHLIBS)
|
||||||
|
|
||||||
|
$(OUTDIR)/%.beam: %.erl
|
||||||
|
@ERLC@ -W $(EFLAGS) -o $(OUTDIR) $<
|
||||||
|
|
||||||
|
#all: $(ERLSHLIBS)
|
||||||
|
# erl -s make all report "{outdir, \"..\"}" -noinput -s erlang halt
|
||||||
|
|
||||||
|
$(ERLSHLIBS): ../%.so: %.c
|
||||||
|
$(CC) -Wall $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) \
|
||||||
|
$(subst ../,,$(subst .so,.c,$@)) $(LIBS) \
|
||||||
|
-o $@ -fpic -shared
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJS) $(ERLSHLIBS)
|
||||||
|
|
||||||
|
distclean: clean
|
||||||
|
rm -f Makefile
|
||||||
|
|
||||||
|
TAGS:
|
||||||
|
etags *.erl
|
134
src/ejabberd_zlib/ejabberd_zlib.erl
Normal file
134
src/ejabberd_zlib/ejabberd_zlib.erl
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
%%% File : ejabberd_zlib.erl
|
||||||
|
%%% Author : Alexey Shchepin <alexey@sevcom.net>
|
||||||
|
%%% Purpose : Interface to zlib
|
||||||
|
%%% Created : 19 Jan 2006 by Alexey Shchepin <alexey@sevcom.net>
|
||||||
|
%%% Id : $Id$
|
||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
|
-module(ejabberd_zlib).
|
||||||
|
-author('alexey@sevcom.net').
|
||||||
|
-vsn('$Revision$ ').
|
||||||
|
|
||||||
|
-behaviour(gen_server).
|
||||||
|
|
||||||
|
-export([start/0, start_link/0,
|
||||||
|
enable_zlib/2, disable_zlib/1,
|
||||||
|
send/2,
|
||||||
|
recv/2, recv/3, recv_data/2,
|
||||||
|
setopts/2,
|
||||||
|
controlling_process/2,
|
||||||
|
close/1]).
|
||||||
|
|
||||||
|
%% Internal exports, call-back functions.
|
||||||
|
-export([init/1,
|
||||||
|
handle_call/3,
|
||||||
|
handle_cast/2,
|
||||||
|
handle_info/2,
|
||||||
|
code_change/3,
|
||||||
|
terminate/2]).
|
||||||
|
|
||||||
|
-define(DEFLATE, 1).
|
||||||
|
-define(INFLATE, 2).
|
||||||
|
|
||||||
|
-record(zlibsock, {sockmod, socket, zlibport}).
|
||||||
|
|
||||||
|
start() ->
|
||||||
|
gen_server:start({local, ?MODULE}, ?MODULE, [], []).
|
||||||
|
|
||||||
|
start_link() ->
|
||||||
|
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
|
||||||
|
|
||||||
|
init([]) ->
|
||||||
|
case erl_ddll:load_driver(ejabberd:get_so_path(), ejabberd_zlib_drv) of
|
||||||
|
ok -> ok;
|
||||||
|
{error, already_loaded} -> ok
|
||||||
|
end,
|
||||||
|
Port = open_port({spawn, ejabberd_zlib_drv}, [binary]),
|
||||||
|
{ok, Port}.
|
||||||
|
|
||||||
|
|
||||||
|
%%% --------------------------------------------------------
|
||||||
|
%%% The call-back functions.
|
||||||
|
%%% --------------------------------------------------------
|
||||||
|
|
||||||
|
handle_call(_, _, State) ->
|
||||||
|
{noreply, State}.
|
||||||
|
|
||||||
|
handle_cast(_, State) ->
|
||||||
|
{noreply, State}.
|
||||||
|
|
||||||
|
handle_info({'EXIT', Port, Reason}, Port) ->
|
||||||
|
{stop, {port_died, Reason}, Port};
|
||||||
|
|
||||||
|
handle_info({'EXIT', _Pid, _Reason}, Port) ->
|
||||||
|
{noreply, Port};
|
||||||
|
|
||||||
|
handle_info(_, State) ->
|
||||||
|
{noreply, State}.
|
||||||
|
|
||||||
|
code_change(_OldVsn, State, _Extra) ->
|
||||||
|
{ok, State}.
|
||||||
|
|
||||||
|
terminate(_Reason, Port) ->
|
||||||
|
Port ! {self, close},
|
||||||
|
ok.
|
||||||
|
|
||||||
|
|
||||||
|
enable_zlib(SockMod, Socket) ->
|
||||||
|
case erl_ddll:load_driver(ejabberd:get_so_path(), ejabberd_zlib_drv) of
|
||||||
|
ok -> ok;
|
||||||
|
{error, already_loaded} -> ok
|
||||||
|
end,
|
||||||
|
Port = open_port({spawn, ejabberd_zlib_drv}, [binary]),
|
||||||
|
{ok, #zlibsock{sockmod = SockMod, socket = Socket, zlibport = Port}}.
|
||||||
|
|
||||||
|
disable_zlib(#zlibsock{sockmod = SockMod, socket = Socket, zlibport = Port}) ->
|
||||||
|
port_close(Port),
|
||||||
|
{SockMod, Socket}.
|
||||||
|
|
||||||
|
recv(Socket, Length) ->
|
||||||
|
recv(Socket, Length, infinity).
|
||||||
|
recv(#zlibsock{sockmod = SockMod, socket = Socket} = ZlibSock,
|
||||||
|
Length, Timeout) ->
|
||||||
|
case SockMod:recv(Socket, Length, Timeout) of
|
||||||
|
{ok, Packet} ->
|
||||||
|
recv_data(ZlibSock, Packet);
|
||||||
|
{error, _Reason} = Error ->
|
||||||
|
Error
|
||||||
|
end.
|
||||||
|
|
||||||
|
recv_data(#zlibsock{zlibport = Port} = _ZlibSock, Packet) ->
|
||||||
|
case port_control(Port, ?INFLATE, Packet) of
|
||||||
|
<<0, In/binary>> ->
|
||||||
|
{ok, In};
|
||||||
|
<<1, Error/binary>> ->
|
||||||
|
{error, binary_to_list(Error)}
|
||||||
|
end.
|
||||||
|
|
||||||
|
send(#zlibsock{sockmod = SockMod, socket = Socket, zlibport = Port},
|
||||||
|
Packet) ->
|
||||||
|
case port_control(Port, ?DEFLATE, Packet) of
|
||||||
|
<<0, Out/binary>> ->
|
||||||
|
SockMod:send(Socket, Out);
|
||||||
|
<<1, Error/binary>> ->
|
||||||
|
{error, binary_to_list(Error)}
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
setopts(#zlibsock{sockmod = SockMod, socket = Socket}, Opts) ->
|
||||||
|
case SockMod of
|
||||||
|
gen_tcp ->
|
||||||
|
inet:setopts(Socket, Opts);
|
||||||
|
_ ->
|
||||||
|
SockMod:setopts(Socket, Opts)
|
||||||
|
end.
|
||||||
|
|
||||||
|
controlling_process(#zlibsock{sockmod = SockMod, socket = Socket}, Pid) ->
|
||||||
|
SockMod:controlling_process(Socket, Pid).
|
||||||
|
|
||||||
|
close(#zlibsock{sockmod = SockMod, socket = Socket, zlibport = Port}) ->
|
||||||
|
SockMod:close(Socket),
|
||||||
|
port_close(Port).
|
||||||
|
|
||||||
|
|
171
src/ejabberd_zlib/ejabberd_zlib_drv.c
Normal file
171
src/ejabberd_zlib/ejabberd_zlib_drv.c
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
/* $Id$ */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <erl_driver.h>
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define BUF_SIZE 1024
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ErlDrvPort port;
|
||||||
|
z_stream *d_stream;
|
||||||
|
z_stream *i_stream;
|
||||||
|
} ejabberd_zlib_data;
|
||||||
|
|
||||||
|
|
||||||
|
static ErlDrvData ejabberd_zlib_drv_start(ErlDrvPort port, char *buff)
|
||||||
|
{
|
||||||
|
ejabberd_zlib_data *d =
|
||||||
|
(ejabberd_zlib_data *)driver_alloc(sizeof(ejabberd_zlib_data));
|
||||||
|
d->port = port;
|
||||||
|
|
||||||
|
d->d_stream = (z_stream *)malloc(sizeof(z_stream));
|
||||||
|
|
||||||
|
d->d_stream->zalloc = (alloc_func)0;
|
||||||
|
d->d_stream->zfree = (free_func)0;
|
||||||
|
d->d_stream->opaque = (voidpf)0;
|
||||||
|
|
||||||
|
deflateInit(d->d_stream, Z_DEFAULT_COMPRESSION);
|
||||||
|
|
||||||
|
d->i_stream = (z_stream *)malloc(sizeof(z_stream));
|
||||||
|
|
||||||
|
d->i_stream->zalloc = (alloc_func)0;
|
||||||
|
d->i_stream->zfree = (free_func)0;
|
||||||
|
d->i_stream->opaque = (voidpf)0;
|
||||||
|
|
||||||
|
inflateInit(d->i_stream);
|
||||||
|
|
||||||
|
set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY);
|
||||||
|
|
||||||
|
return (ErlDrvData)d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ejabberd_zlib_drv_stop(ErlDrvData handle)
|
||||||
|
{
|
||||||
|
ejabberd_zlib_data *d = (ejabberd_zlib_data *)handle;
|
||||||
|
|
||||||
|
deflateEnd(d->d_stream);
|
||||||
|
free(d->d_stream);
|
||||||
|
|
||||||
|
inflateEnd(d->i_stream);
|
||||||
|
free(d->i_stream);
|
||||||
|
|
||||||
|
driver_free((char *)handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define DEFLATE 1
|
||||||
|
#define INFLATE 2
|
||||||
|
|
||||||
|
#define die_unless(cond, errstr) \
|
||||||
|
if (!(cond)) \
|
||||||
|
{ \
|
||||||
|
rlen = strlen(errstr) + 1; \
|
||||||
|
b = driver_realloc_binary(b, rlen); \
|
||||||
|
b->orig_bytes[0] = 1; \
|
||||||
|
strncpy(b->orig_bytes + 1, errstr, rlen - 1); \
|
||||||
|
*rbuf = (char *)b; \
|
||||||
|
return rlen; \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int ejabberd_zlib_drv_control(ErlDrvData handle,
|
||||||
|
unsigned int command,
|
||||||
|
char *buf, int len,
|
||||||
|
char **rbuf, int rlen)
|
||||||
|
{
|
||||||
|
ejabberd_zlib_data *d = (ejabberd_zlib_data *)handle;
|
||||||
|
int err;
|
||||||
|
int size;
|
||||||
|
ErlDrvBinary *b;
|
||||||
|
|
||||||
|
switch (command)
|
||||||
|
{
|
||||||
|
case DEFLATE:
|
||||||
|
size = BUF_SIZE + 1;
|
||||||
|
rlen = 1;
|
||||||
|
b = driver_alloc_binary(size);
|
||||||
|
b->orig_bytes[0] = 0;
|
||||||
|
|
||||||
|
d->d_stream->next_in = buf;
|
||||||
|
d->d_stream->avail_in = len;
|
||||||
|
d->d_stream->avail_out = 0;
|
||||||
|
err = Z_OK;
|
||||||
|
|
||||||
|
while (err == Z_OK && d->d_stream->avail_out == 0)
|
||||||
|
{
|
||||||
|
d->d_stream->next_out = b->orig_bytes + rlen;
|
||||||
|
d->d_stream->avail_out = BUF_SIZE;
|
||||||
|
|
||||||
|
err = deflate(d->d_stream, Z_SYNC_FLUSH);
|
||||||
|
die_unless((err == Z_OK) || (err == Z_STREAM_END),
|
||||||
|
"Deflate error");
|
||||||
|
|
||||||
|
rlen += (BUF_SIZE - d->d_stream->avail_out);
|
||||||
|
size += (BUF_SIZE - d->d_stream->avail_out);
|
||||||
|
b = driver_realloc_binary(b, size);
|
||||||
|
}
|
||||||
|
b = driver_realloc_binary(b, rlen);
|
||||||
|
*rbuf = (char *)b;
|
||||||
|
return rlen;
|
||||||
|
case INFLATE:
|
||||||
|
size = BUF_SIZE + 1;
|
||||||
|
rlen = 1;
|
||||||
|
b = driver_alloc_binary(size);
|
||||||
|
b->orig_bytes[0] = 0;
|
||||||
|
|
||||||
|
if (len > 0) {
|
||||||
|
d->i_stream->next_in = buf;
|
||||||
|
d->i_stream->avail_in = len;
|
||||||
|
d->i_stream->avail_out = 0;
|
||||||
|
err = Z_OK;
|
||||||
|
|
||||||
|
while (err == Z_OK && d->i_stream->avail_out == 0)
|
||||||
|
{
|
||||||
|
d->i_stream->next_out = b->orig_bytes + rlen;
|
||||||
|
d->i_stream->avail_out = BUF_SIZE;
|
||||||
|
|
||||||
|
err = inflate(d->i_stream, Z_SYNC_FLUSH);
|
||||||
|
die_unless((err == Z_OK) || (err == Z_STREAM_END),
|
||||||
|
"Inflate error");
|
||||||
|
|
||||||
|
rlen += (BUF_SIZE - d->i_stream->avail_out);
|
||||||
|
size += (BUF_SIZE - d->i_stream->avail_out);
|
||||||
|
b = driver_realloc_binary(b, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b = driver_realloc_binary(b, rlen);
|
||||||
|
*rbuf = (char *)b;
|
||||||
|
return rlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
b = driver_alloc_binary(1);
|
||||||
|
b->orig_bytes[0] = 0;
|
||||||
|
*rbuf = (char *)b;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ErlDrvEntry ejabberd_zlib_driver_entry = {
|
||||||
|
NULL, /* F_PTR init, N/A */
|
||||||
|
ejabberd_zlib_drv_start, /* L_PTR start, called when port is opened */
|
||||||
|
ejabberd_zlib_drv_stop, /* F_PTR stop, called when port is closed */
|
||||||
|
NULL, /* F_PTR output, called when erlang has sent */
|
||||||
|
NULL, /* F_PTR ready_input, called when input descriptor ready */
|
||||||
|
NULL, /* F_PTR ready_output, called when output descriptor ready */
|
||||||
|
"ejabberd_zlib_drv", /* char *driver_name, the argument to open_port */
|
||||||
|
NULL, /* F_PTR finish, called when unloaded */
|
||||||
|
NULL, /* handle */
|
||||||
|
ejabberd_zlib_drv_control, /* F_PTR control, port_command callback */
|
||||||
|
NULL, /* F_PTR timeout, reserved */
|
||||||
|
NULL /* F_PTR outputv, reserved */
|
||||||
|
};
|
||||||
|
|
||||||
|
DRIVER_INIT(ejabberd_zlib_drv) /* must match name in driver_entry */
|
||||||
|
{
|
||||||
|
return &ejabberd_zlib_driver_entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -19,7 +19,8 @@
|
|||||||
loaded_modules/1,
|
loaded_modules/1,
|
||||||
loaded_modules_with_opts/1,
|
loaded_modules_with_opts/1,
|
||||||
get_hosts/2,
|
get_hosts/2,
|
||||||
get_module_proc/2]).
|
get_module_proc/2,
|
||||||
|
is_loaded/2]).
|
||||||
|
|
||||||
-export([behaviour_info/1]).
|
-export([behaviour_info/1]).
|
||||||
|
|
||||||
@ -144,3 +145,6 @@ get_hosts(Opts, Prefix) ->
|
|||||||
get_module_proc(Host, Base) ->
|
get_module_proc(Host, Base) ->
|
||||||
list_to_atom(atom_to_list(Base) ++ "_" ++ Host).
|
list_to_atom(atom_to_list(Base) ++ "_" ++ Host).
|
||||||
|
|
||||||
|
is_loaded(Host, Module) ->
|
||||||
|
ets:member(ejabberd_modules, {Module, Host}).
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
-define(NS_PUBSUB_EVENT, "http://jabber.org/protocol/pubsub#event").
|
-define(NS_PUBSUB_EVENT, "http://jabber.org/protocol/pubsub#event").
|
||||||
-define(NS_PUBSUB_OWNER, "http://jabber.org/protocol/pubsub#owner").
|
-define(NS_PUBSUB_OWNER, "http://jabber.org/protocol/pubsub#owner").
|
||||||
-define(NS_PUBSUB_NMI, "http://jabber.org/protocol/pubsub#node-meta-info").
|
-define(NS_PUBSUB_NMI, "http://jabber.org/protocol/pubsub#node-meta-info").
|
||||||
|
-define(NS_COMMANDS, "http://jabber.org/protocol/commands").
|
||||||
|
|
||||||
-define(NS_EJABBERD_CONFIG, "ejabberd:config").
|
-define(NS_EJABBERD_CONFIG, "ejabberd:config").
|
||||||
|
|
||||||
@ -48,6 +49,9 @@
|
|||||||
|
|
||||||
-define(NS_FEATURE_IQAUTH, "http://jabber.org/features/iq-auth").
|
-define(NS_FEATURE_IQAUTH, "http://jabber.org/features/iq-auth").
|
||||||
-define(NS_FEATURE_IQREGISTER, "http://jabber.org/features/iq-register").
|
-define(NS_FEATURE_IQREGISTER, "http://jabber.org/features/iq-register").
|
||||||
|
-define(NS_FEATURE_COMPRESS, "http://jabber.org/features/compress").
|
||||||
|
|
||||||
|
-define(NS_COMPRESS, "http://jabber.org/protocol/compress").
|
||||||
|
|
||||||
% TODO: remove "code" attribute (currently it used for backward-compatibility)
|
% TODO: remove "code" attribute (currently it used for backward-compatibility)
|
||||||
-define(STANZA_ERROR(Code, Type, Condition),
|
-define(STANZA_ERROR(Code, Type, Condition),
|
||||||
|
250
src/mod_adhoc.erl
Normal file
250
src/mod_adhoc.erl
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
%%% File : mod_adhoc.erl
|
||||||
|
%%% Author : Magnus Henoch <henoch@dtek.chalmers.se>
|
||||||
|
%%% Purpose : Handle incoming ad-doc requests (JEP-0050)
|
||||||
|
%%% Created : 15 Nov 2005 by Magnus Henoch <henoch@dtek.chalmers.se>
|
||||||
|
%%% Id : $Id$
|
||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
|
-module(mod_adhoc).
|
||||||
|
-author('henoch@dtek.chalmers.se').
|
||||||
|
-vsn('$Revision$ ').
|
||||||
|
|
||||||
|
-behaviour(gen_mod).
|
||||||
|
|
||||||
|
-export([start/2,
|
||||||
|
stop/1,
|
||||||
|
process_local_iq/3,
|
||||||
|
process_sm_iq/3,
|
||||||
|
get_local_commands/5,
|
||||||
|
get_local_identity/5,
|
||||||
|
get_local_features/5,
|
||||||
|
get_sm_commands/5,
|
||||||
|
get_sm_identity/5,
|
||||||
|
get_sm_features/5,
|
||||||
|
ping_item/4,
|
||||||
|
ping_command/4]).
|
||||||
|
|
||||||
|
-include("ejabberd.hrl").
|
||||||
|
-include("jlib.hrl").
|
||||||
|
-include("adhoc.hrl").
|
||||||
|
|
||||||
|
start(Host, Opts) ->
|
||||||
|
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
|
||||||
|
|
||||||
|
gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_COMMANDS,
|
||||||
|
?MODULE, process_local_iq, IQDisc),
|
||||||
|
gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_COMMANDS,
|
||||||
|
?MODULE, process_sm_iq, IQDisc),
|
||||||
|
|
||||||
|
ejabberd_hooks:add(disco_local_identity, Host, ?MODULE, get_local_identity, 99),
|
||||||
|
ejabberd_hooks:add(disco_local_features, Host, ?MODULE, get_local_features, 99),
|
||||||
|
ejabberd_hooks:add(disco_local_items, Host, ?MODULE, get_local_commands, 99),
|
||||||
|
ejabberd_hooks:add(disco_sm_identity, Host, ?MODULE, get_sm_identity, 99),
|
||||||
|
ejabberd_hooks:add(disco_sm_features, Host, ?MODULE, get_sm_features, 99),
|
||||||
|
ejabberd_hooks:add(disco_sm_items, Host, ?MODULE, get_sm_commands, 99),
|
||||||
|
ejabberd_hooks:add(adhoc_local_items, Host, ?MODULE, ping_item, 100),
|
||||||
|
ejabberd_hooks:add(adhoc_local_commands, Host, ?MODULE, ping_command, 100).
|
||||||
|
|
||||||
|
stop(Host) ->
|
||||||
|
ejabberd_hooks:delete(adhoc_local_commands, Host, ?MODULE, ping_command, 100),
|
||||||
|
ejabberd_hooks:delete(adhoc_local_items, Host, ?MODULE, ping_item, 100),
|
||||||
|
ejabberd_hooks:delete(disco_sm_items, Host, ?MODULE, get_sm_commands, 99),
|
||||||
|
ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, get_sm_features, 99),
|
||||||
|
ejabberd_hooks:delete(disco_sm_identity, Host, ?MODULE, get_sm_identity, 99),
|
||||||
|
ejabberd_hooks:delete(disco_local_items, Host, ?MODULE, get_local_commands, 99),
|
||||||
|
ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, get_local_features, 99),
|
||||||
|
ejabberd_hooks:delete(disco_local_identity, Host, ?MODULE, get_local_identity, 99),
|
||||||
|
|
||||||
|
gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_COMMANDS),
|
||||||
|
gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_COMMANDS).
|
||||||
|
|
||||||
|
%-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
get_local_commands(Acc, _From, #jid{server = Server, lserver = LServer} = _To, "", Lang) ->
|
||||||
|
Display = gen_mod:get_module_opt(LServer, ?MODULE, report_commands_node, false),
|
||||||
|
case Display of
|
||||||
|
false ->
|
||||||
|
Acc;
|
||||||
|
_ ->
|
||||||
|
Items = case Acc of
|
||||||
|
{result, I} -> I;
|
||||||
|
_ -> []
|
||||||
|
end,
|
||||||
|
Nodes = [{xmlelement,
|
||||||
|
"item",
|
||||||
|
[{"jid", Server},
|
||||||
|
{"node", ?NS_COMMANDS},
|
||||||
|
{"name", translate:translate(Lang, "Commands")}],
|
||||||
|
[]}],
|
||||||
|
{result, Items ++ Nodes}
|
||||||
|
end;
|
||||||
|
|
||||||
|
get_local_commands(_Acc, From, #jid{lserver = LServer} = To, ?NS_COMMANDS, Lang) ->
|
||||||
|
ejabberd_hooks:run_fold(adhoc_local_items, LServer, {result, []}, [From, To, Lang]);
|
||||||
|
|
||||||
|
get_local_commands(_Acc, _From, _To, "ping", _Lang) ->
|
||||||
|
{result, []};
|
||||||
|
|
||||||
|
get_local_commands(Acc, _From, _To, _Node, _Lang) ->
|
||||||
|
Acc.
|
||||||
|
|
||||||
|
%-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
get_sm_commands(Acc, _From, #jid{lserver = LServer} = To, "", Lang) ->
|
||||||
|
Display = gen_mod:get_module_opt(LServer, ?MODULE, report_commands_node, false),
|
||||||
|
case Display of
|
||||||
|
false ->
|
||||||
|
Acc;
|
||||||
|
_ ->
|
||||||
|
Items = case Acc of
|
||||||
|
{result, I} -> I;
|
||||||
|
_ -> []
|
||||||
|
end,
|
||||||
|
Nodes = [{xmlelement,
|
||||||
|
"item",
|
||||||
|
[{"jid", jlib:jid_to_string(To)},
|
||||||
|
{"node", ?NS_COMMANDS},
|
||||||
|
{"name", translate:translate(Lang, "Commands")}],
|
||||||
|
[]}],
|
||||||
|
{result, Items ++ Nodes}
|
||||||
|
end;
|
||||||
|
|
||||||
|
get_sm_commands(_Acc, From, #jid{lserver = LServer} = To, ?NS_COMMANDS, Lang) ->
|
||||||
|
ejabberd_hooks:run_fold(adhoc_sm_items, LServer, {result, []}, [From, To, Lang]);
|
||||||
|
|
||||||
|
get_sm_commands(Acc, _From, _To, _Node, _Lang) ->
|
||||||
|
Acc.
|
||||||
|
|
||||||
|
%-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
%% On disco info request to the ad-hoc node, return automation/command-list.
|
||||||
|
get_local_identity(Acc, _From, _To, ?NS_COMMANDS, Lang) ->
|
||||||
|
[{xmlelement, "identity",
|
||||||
|
[{"category", "automation"},
|
||||||
|
{"type", "command-list"},
|
||||||
|
{"name", translate:translate(Lang, "Commands")}], []} | Acc];
|
||||||
|
|
||||||
|
get_local_identity(Acc, _From, _To, "ping", Lang) ->
|
||||||
|
[{xmlelement, "identity",
|
||||||
|
[{"category", "automation"},
|
||||||
|
{"type", "command-node"},
|
||||||
|
{"name", translate:translate(Lang, "Ping")}], []} | Acc];
|
||||||
|
|
||||||
|
get_local_identity(Acc, _From, _To, _Node, _Lang) ->
|
||||||
|
Acc.
|
||||||
|
|
||||||
|
%-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
%% On disco info request to the ad-hoc node, return automation/command-list.
|
||||||
|
get_sm_identity(Acc, _From, _To, ?NS_COMMANDS, Lang) ->
|
||||||
|
[{xmlelement, "identity",
|
||||||
|
[{"category", "automation"},
|
||||||
|
{"type", "command-list"},
|
||||||
|
{"name", translate:translate(Lang, "Commands")}], []} | Acc];
|
||||||
|
|
||||||
|
get_sm_identity(Acc, _From, _To, _Node, _Lang) ->
|
||||||
|
Acc.
|
||||||
|
|
||||||
|
%-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
get_local_features(Acc, _From, _To, "", _Lang) ->
|
||||||
|
Feats = case Acc of
|
||||||
|
{result, I} -> I;
|
||||||
|
_ -> []
|
||||||
|
end,
|
||||||
|
{result, Feats ++ [?NS_COMMANDS]};
|
||||||
|
|
||||||
|
get_local_features(_Acc, _From, _To, ?NS_COMMANDS, _Lang) ->
|
||||||
|
%% override all lesser features...
|
||||||
|
{result, []};
|
||||||
|
|
||||||
|
get_local_features(_Acc, _From, _To, "ping", _Lang) ->
|
||||||
|
%% override all lesser features...
|
||||||
|
{result, [?NS_COMMANDS]};
|
||||||
|
|
||||||
|
get_local_features(Acc, _From, _To, _Node, _Lang) ->
|
||||||
|
Acc.
|
||||||
|
|
||||||
|
%-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
get_sm_features(Acc, _From, _To, "", _Lang) ->
|
||||||
|
Feats = case Acc of
|
||||||
|
{result, I} -> I;
|
||||||
|
_ -> []
|
||||||
|
end,
|
||||||
|
{result, Feats ++ [?NS_COMMANDS]};
|
||||||
|
|
||||||
|
get_sm_features(_Acc, _From, _To, ?NS_COMMANDS, _Lang) ->
|
||||||
|
%% override all lesser features...
|
||||||
|
{result, []};
|
||||||
|
|
||||||
|
get_sm_features(Acc, _From, _To, _Node, _Lang) ->
|
||||||
|
Acc.
|
||||||
|
|
||||||
|
%-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
process_local_iq(From, To, IQ) ->
|
||||||
|
process_adhoc_request(From, To, IQ, adhoc_local_commands).
|
||||||
|
|
||||||
|
|
||||||
|
process_sm_iq(From, To, IQ) ->
|
||||||
|
process_adhoc_request(From, To, IQ, adhoc_sm_commands).
|
||||||
|
|
||||||
|
|
||||||
|
process_adhoc_request(From, To, #iq{sub_el = SubEl} = IQ, Hook) ->
|
||||||
|
?DEBUG("About to parse ~p...", [IQ]),
|
||||||
|
case adhoc:parse_request(IQ) of
|
||||||
|
{error, Error} ->
|
||||||
|
IQ#iq{type = error, sub_el = [SubEl, Error]};
|
||||||
|
#adhoc_request{} = AdhocRequest ->
|
||||||
|
Host = To#jid.lserver,
|
||||||
|
case ejabberd_hooks:run_fold(Hook, Host, empty,
|
||||||
|
[From, To, AdhocRequest]) of
|
||||||
|
ignore ->
|
||||||
|
ignore;
|
||||||
|
empty ->
|
||||||
|
IQ#iq{type = error, sub_el = [SubEl, ?ERR_ITEM_NOT_FOUND]};
|
||||||
|
{error, Error} ->
|
||||||
|
IQ#iq{type = error, sub_el = [SubEl, Error]};
|
||||||
|
Command ->
|
||||||
|
IQ#iq{type = result, sub_el = [Command]}
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
ping_item(Acc, _From, #jid{server = Server} = _To, Lang) ->
|
||||||
|
Items = case Acc of
|
||||||
|
{result, I} ->
|
||||||
|
I;
|
||||||
|
_ ->
|
||||||
|
[]
|
||||||
|
end,
|
||||||
|
Nodes = [{xmlelement, "item",
|
||||||
|
[{"jid", Server},
|
||||||
|
{"node", "ping"},
|
||||||
|
{"name", translate:translate(Lang, "Ping")}],
|
||||||
|
[]}],
|
||||||
|
{result, Items ++ Nodes}.
|
||||||
|
|
||||||
|
|
||||||
|
ping_command(_Acc, _From, _To,
|
||||||
|
#adhoc_request{lang = Lang,
|
||||||
|
node = "ping",
|
||||||
|
sessionid = _Sessionid,
|
||||||
|
action = Action} = Request) ->
|
||||||
|
if
|
||||||
|
Action == ""; Action == "execute" ->
|
||||||
|
adhoc:produce_response(
|
||||||
|
Request,
|
||||||
|
#adhoc_response{status = completed,
|
||||||
|
notes = [{"info", translate:translate(
|
||||||
|
Lang,
|
||||||
|
"Pong")}]});
|
||||||
|
true ->
|
||||||
|
{error, ?ERR_BAD_REQUEST}
|
||||||
|
end;
|
||||||
|
|
||||||
|
ping_command(Acc, _From, _To, _Request) ->
|
||||||
|
Acc.
|
||||||
|
|
@ -15,10 +15,16 @@
|
|||||||
init/0,
|
init/0,
|
||||||
stop/1,
|
stop/1,
|
||||||
announce/3,
|
announce/3,
|
||||||
send_motd/1]).
|
send_motd/1,
|
||||||
|
disco_identity/5,
|
||||||
|
disco_features/5,
|
||||||
|
disco_items/5,
|
||||||
|
announce_commands/4,
|
||||||
|
announce_items/4]).
|
||||||
|
|
||||||
-include("ejabberd.hrl").
|
-include("ejabberd.hrl").
|
||||||
-include("jlib.hrl").
|
-include("jlib.hrl").
|
||||||
|
-include("adhoc.hrl").
|
||||||
|
|
||||||
-record(motd, {server, packet}).
|
-record(motd, {server, packet}).
|
||||||
-record(motd_users, {us, dummy = []}).
|
-record(motd_users, {us, dummy = []}).
|
||||||
@ -33,6 +39,11 @@ start(Host, _Opts) ->
|
|||||||
update_tables(),
|
update_tables(),
|
||||||
ejabberd_hooks:add(local_send_to_resource_hook, Host,
|
ejabberd_hooks:add(local_send_to_resource_hook, Host,
|
||||||
?MODULE, announce, 50),
|
?MODULE, announce, 50),
|
||||||
|
ejabberd_hooks:add(disco_local_identity, Host, ?MODULE, disco_identity, 50),
|
||||||
|
ejabberd_hooks:add(disco_local_features, Host, ?MODULE, disco_features, 50),
|
||||||
|
ejabberd_hooks:add(disco_local_items, Host, ?MODULE, disco_items, 50),
|
||||||
|
ejabberd_hooks:add(adhoc_local_items, Host, ?MODULE, announce_items, 50),
|
||||||
|
ejabberd_hooks:add(adhoc_local_commands, Host, ?MODULE, announce_commands, 50),
|
||||||
ejabberd_hooks:add(user_available_hook, Host,
|
ejabberd_hooks:add(user_available_hook, Host,
|
||||||
?MODULE, send_motd, 50),
|
?MODULE, send_motd, 50),
|
||||||
register(gen_mod:get_module_proc(Host, ?PROCNAME),
|
register(gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||||
@ -66,6 +77,11 @@ loop() ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
stop(Host) ->
|
stop(Host) ->
|
||||||
|
ejabberd_hooks:delete(adhoc_local_commands, Host, ?MODULE, announce_commands, 50),
|
||||||
|
ejabberd_hooks:delete(adhoc_local_items, Host, ?MODULE, announce_items, 50),
|
||||||
|
ejabberd_hooks:delete(disco_local_identity, Host, ?MODULE, disco_identity, 50),
|
||||||
|
ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, disco_features, 50),
|
||||||
|
ejabberd_hooks:delete(disco_local_items, Host, ?MODULE, disco_items, 50),
|
||||||
ejabberd_hooks:delete(local_send_to_resource_hook, Host,
|
ejabberd_hooks:delete(local_send_to_resource_hook, Host,
|
||||||
?MODULE, announce, 50),
|
?MODULE, announce, 50),
|
||||||
ejabberd_hooks:delete(sm_register_connection_hook, Host,
|
ejabberd_hooks:delete(sm_register_connection_hook, Host,
|
||||||
@ -74,6 +90,7 @@ stop(Host) ->
|
|||||||
exit(whereis(Proc), stop),
|
exit(whereis(Proc), stop),
|
||||||
{wait, Proc}.
|
{wait, Proc}.
|
||||||
|
|
||||||
|
% Announcing via messages to a custom resource
|
||||||
announce(From, To, Packet) ->
|
announce(From, To, Packet) ->
|
||||||
case To of
|
case To of
|
||||||
#jid{luser = "", lresource = Res} ->
|
#jid{luser = "", lresource = Res} ->
|
||||||
@ -105,12 +122,422 @@ announce(From, To, Packet) ->
|
|||||||
ok
|
ok
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
%-------------------------------------------------------------------------
|
||||||
|
% Announcing via ad-hoc commands
|
||||||
|
-define(INFO_COMMAND(Lang, Node),
|
||||||
|
[{xmlelement, "identity",
|
||||||
|
[{"category", "automation"},
|
||||||
|
{"type", "command-node"},
|
||||||
|
{"name", get_title(Lang, Node)}], []}]).
|
||||||
|
|
||||||
|
disco_identity(Acc, _From, _To, Node, Lang) ->
|
||||||
|
case Node of
|
||||||
|
"announce/all" ->
|
||||||
|
?INFO_COMMAND(Lang, Node);
|
||||||
|
"announce/all-hosts/online" ->
|
||||||
|
?INFO_COMMAND(Lang, Node);
|
||||||
|
"announce/online" ->
|
||||||
|
?INFO_COMMAND(Lang, Node);
|
||||||
|
"announce/motd" ->
|
||||||
|
?INFO_COMMAND(Lang, Node);
|
||||||
|
"announce/motd/delete" ->
|
||||||
|
?INFO_COMMAND(Lang, Node);
|
||||||
|
"announce/motd/update" ->
|
||||||
|
?INFO_COMMAND(Lang, Node);
|
||||||
|
_ ->
|
||||||
|
Acc
|
||||||
|
end.
|
||||||
|
|
||||||
|
%-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-define(INFO_RESULT(Allow, Feats),
|
||||||
|
case Allow of
|
||||||
|
deny ->
|
||||||
|
{error, ?ERR_FORBIDDEN};
|
||||||
|
allow ->
|
||||||
|
{result, Feats}
|
||||||
|
end).
|
||||||
|
|
||||||
|
disco_features(Acc, From, #jid{lserver = LServer} = _To,
|
||||||
|
"announce", _Lang) ->
|
||||||
|
case gen_mod:is_loaded(LServer, mod_adhoc) of
|
||||||
|
false ->
|
||||||
|
Acc;
|
||||||
|
_ ->
|
||||||
|
Access1 = gen_mod:get_module_opt(LServer, ?MODULE, access, none),
|
||||||
|
Access2 = gen_mod:get_module_opt(global, ?MODULE, access, none),
|
||||||
|
case {acl:match_rule(LServer, Access1, From),
|
||||||
|
acl:match_rule(global, Access2, From)} of
|
||||||
|
{deny, deny} ->
|
||||||
|
{error, ?ERR_FORBIDDEN};
|
||||||
|
_ ->
|
||||||
|
{result, []}
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
disco_features(Acc, From, #jid{lserver = LServer} = _To,
|
||||||
|
"announce/all-hosts/online", _Lang) ->
|
||||||
|
case gen_mod:is_loaded(LServer, mod_adhoc) of
|
||||||
|
false ->
|
||||||
|
Acc;
|
||||||
|
_ ->
|
||||||
|
Access = gen_mod:get_module_opt(global, ?MODULE, access, none),
|
||||||
|
Allow = acl:match_rule(global, Access, From),
|
||||||
|
?INFO_RESULT(Allow, [?NS_COMMANDS])
|
||||||
|
end;
|
||||||
|
|
||||||
|
disco_features(Acc, From, #jid{lserver = LServer} = _To,
|
||||||
|
Node, _Lang) ->
|
||||||
|
case gen_mod:is_loaded(LServer, mod_adhoc) of
|
||||||
|
false ->
|
||||||
|
Acc;
|
||||||
|
_ ->
|
||||||
|
Access = gen_mod:get_module_opt(LServer, ?MODULE, access, none),
|
||||||
|
Allow = acl:match_rule(LServer, Access, From),
|
||||||
|
case Node of
|
||||||
|
"announce/all" ->
|
||||||
|
?INFO_RESULT(Allow, [?NS_COMMANDS]);
|
||||||
|
"announce/online" ->
|
||||||
|
?INFO_RESULT(Allow, [?NS_COMMANDS]);
|
||||||
|
"announce/motd" ->
|
||||||
|
?INFO_RESULT(Allow, [?NS_COMMANDS]);
|
||||||
|
"announce/motd/delete" ->
|
||||||
|
?INFO_RESULT(Allow, [?NS_COMMANDS]);
|
||||||
|
"announce/motd/update" ->
|
||||||
|
?INFO_RESULT(Allow, [?NS_COMMANDS]);
|
||||||
|
_ ->
|
||||||
|
Acc
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
|
%-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-define(NODE_TO_ITEM(Lang, Server, Node),
|
||||||
|
{xmlelement, "item",
|
||||||
|
[{"jid", Server},
|
||||||
|
{"node", Node},
|
||||||
|
{"name", get_title(Lang, Node)}],
|
||||||
|
[]}).
|
||||||
|
|
||||||
|
-define(ITEMS_RESULT(Allow, Items),
|
||||||
|
case Allow of
|
||||||
|
deny ->
|
||||||
|
{error, ?ERR_FORBIDDEN};
|
||||||
|
allow ->
|
||||||
|
{result, Items}
|
||||||
|
end).
|
||||||
|
|
||||||
|
disco_items(Acc, From, #jid{lserver = LServer, server = Server} = _To,
|
||||||
|
"", Lang) ->
|
||||||
|
case gen_mod:is_loaded(LServer, mod_adhoc) of
|
||||||
|
false ->
|
||||||
|
Acc;
|
||||||
|
_ ->
|
||||||
|
Access1 = gen_mod:get_module_opt(LServer, ?MODULE, access, none),
|
||||||
|
Access2 = gen_mod:get_module_opt(global, ?MODULE, access, none),
|
||||||
|
case {acl:match_rule(LServer, Access1, From),
|
||||||
|
acl:match_rule(global, Access2, From)} of
|
||||||
|
{deny, deny} ->
|
||||||
|
Acc;
|
||||||
|
_ ->
|
||||||
|
Items = case Acc of
|
||||||
|
{result, I} -> I;
|
||||||
|
_ -> []
|
||||||
|
end,
|
||||||
|
Nodes = [?NODE_TO_ITEM(Lang, Server, "announce")],
|
||||||
|
{result, Items ++ Nodes}
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
disco_items(Acc, From, #jid{lserver = LServer} = To, "announce", Lang) ->
|
||||||
|
case gen_mod:is_loaded(LServer, mod_adhoc) of
|
||||||
|
false ->
|
||||||
|
Acc;
|
||||||
|
_ ->
|
||||||
|
announce_items(Acc, From, To, Lang)
|
||||||
|
end;
|
||||||
|
|
||||||
|
disco_items(Acc, From, #jid{lserver = LServer} = _To,
|
||||||
|
"announce/all-hosts/online", _Lang) ->
|
||||||
|
case gen_mod:is_loaded(LServer, mod_adhoc) of
|
||||||
|
false ->
|
||||||
|
Acc;
|
||||||
|
_ ->
|
||||||
|
Access = gen_mod:get_module_opt(global, ?MODULE, access, none),
|
||||||
|
Allow = acl:match_rule(global, Access, From),
|
||||||
|
?ITEMS_RESULT(Allow, [])
|
||||||
|
end;
|
||||||
|
|
||||||
|
disco_items(Acc, From, #jid{lserver = LServer} = _To, Node, _Lang) ->
|
||||||
|
case gen_mod:is_loaded(LServer, mod_adhoc) of
|
||||||
|
false ->
|
||||||
|
Acc;
|
||||||
|
_ ->
|
||||||
|
Access = gen_mod:get_module_opt(LServer, ?MODULE, access, none),
|
||||||
|
Allow = acl:match_rule(LServer, Access, From),
|
||||||
|
case Node of
|
||||||
|
"announce/all" ->
|
||||||
|
?ITEMS_RESULT(Allow, []);
|
||||||
|
"announce/online" ->
|
||||||
|
?ITEMS_RESULT(Allow, []);
|
||||||
|
"announce/motd" ->
|
||||||
|
?ITEMS_RESULT(Allow, []);
|
||||||
|
"announce/motd/delete" ->
|
||||||
|
?ITEMS_RESULT(Allow, []);
|
||||||
|
"announce/motd/update" ->
|
||||||
|
?ITEMS_RESULT(Allow, []);
|
||||||
|
_ ->
|
||||||
|
Acc
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
|
%-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
announce_items(Acc, From, #jid{lserver = LServer, server = Server} = _To, Lang) ->
|
||||||
|
Access1 = gen_mod:get_module_opt(LServer, ?MODULE, access, none),
|
||||||
|
Nodes1 = case acl:match_rule(LServer, Access1, From) of
|
||||||
|
allow ->
|
||||||
|
[?NODE_TO_ITEM(Lang, Server, "announce/all"),
|
||||||
|
?NODE_TO_ITEM(Lang, Server, "announce/online"),
|
||||||
|
?NODE_TO_ITEM(Lang, Server, "announce/motd"),
|
||||||
|
?NODE_TO_ITEM(Lang, Server, "announce/motd/delete"),
|
||||||
|
?NODE_TO_ITEM(Lang, Server, "announce/motd/update")];
|
||||||
|
deny ->
|
||||||
|
[]
|
||||||
|
end,
|
||||||
|
Access2 = gen_mod:get_module_opt(global, ?MODULE, access, none),
|
||||||
|
Nodes2 = case acl:match_rule(global, Access2, From) of
|
||||||
|
allow ->
|
||||||
|
[?NODE_TO_ITEM(Lang, Server, "announce/all-hosts/online")];
|
||||||
|
deny ->
|
||||||
|
[]
|
||||||
|
end,
|
||||||
|
case {Nodes1, Nodes2} of
|
||||||
|
{[], []} ->
|
||||||
|
Acc;
|
||||||
|
_ ->
|
||||||
|
Items = case Acc of
|
||||||
|
{result, I} -> I;
|
||||||
|
_ -> []
|
||||||
|
end,
|
||||||
|
{result, Items ++ Nodes1 ++ Nodes2}
|
||||||
|
end.
|
||||||
|
|
||||||
|
%-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-define(COMMANDS_RESULT(Allow, From, To, Request),
|
||||||
|
case Allow of
|
||||||
|
deny ->
|
||||||
|
{error, ?ERR_FORBIDDEN};
|
||||||
|
allow ->
|
||||||
|
announce_commands(From, To, Request)
|
||||||
|
end).
|
||||||
|
|
||||||
|
announce_commands(_Acc, From, To,
|
||||||
|
#adhoc_request{
|
||||||
|
node = "announce/all-hosts/online"} = Request) ->
|
||||||
|
Access = gen_mod:get_module_opt(global, ?MODULE, access, none),
|
||||||
|
Allow = acl:match_rule(global, Access, From),
|
||||||
|
?COMMANDS_RESULT(Allow, From, To, Request);
|
||||||
|
|
||||||
|
announce_commands(Acc, From, #jid{lserver = LServer} = To,
|
||||||
|
#adhoc_request{node = Node} = Request) ->
|
||||||
|
Access = gen_mod:get_module_opt(LServer, ?MODULE, access, none),
|
||||||
|
Allow = acl:match_rule(LServer, Access, From),
|
||||||
|
case Node of
|
||||||
|
"announce/all" ->
|
||||||
|
?COMMANDS_RESULT(Allow, From, To, Request);
|
||||||
|
"announce/online" ->
|
||||||
|
?COMMANDS_RESULT(Allow, From, To, Request);
|
||||||
|
"announce/motd" ->
|
||||||
|
?COMMANDS_RESULT(Allow, From, To, Request);
|
||||||
|
"announce/motd/delete" ->
|
||||||
|
?COMMANDS_RESULT(Allow, From, To, Request);
|
||||||
|
"announce/motd/update" ->
|
||||||
|
?COMMANDS_RESULT(Allow, From, To, Request);
|
||||||
|
_ ->
|
||||||
|
Acc
|
||||||
|
end.
|
||||||
|
|
||||||
|
%-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
announce_commands(From, To,
|
||||||
|
#adhoc_request{lang = Lang,
|
||||||
|
node = Node,
|
||||||
|
action = Action,
|
||||||
|
xdata = XData} = Request) ->
|
||||||
|
%% If the "action" attribute is not present, it is
|
||||||
|
%% understood as "execute". If there was no <actions/>
|
||||||
|
%% element in the first response (which there isn't in our
|
||||||
|
%% case), "execute" and "complete" are equivalent.
|
||||||
|
ActionIsExecute = lists:member(Action,
|
||||||
|
["", "execute", "complete"]),
|
||||||
|
if Action == "cancel" ->
|
||||||
|
%% User cancels request
|
||||||
|
adhoc:produce_response(Request,
|
||||||
|
#adhoc_response{status = canceled});
|
||||||
|
XData == false, ActionIsExecute ->
|
||||||
|
%% User requests form
|
||||||
|
adhoc:produce_response(
|
||||||
|
Request,
|
||||||
|
#adhoc_response{status = executing,
|
||||||
|
elements = [generate_adhoc_form(Lang, Node)]});
|
||||||
|
XData /= false, ActionIsExecute ->
|
||||||
|
%% User returns form.
|
||||||
|
case jlib:parse_xdata_submit(XData) of
|
||||||
|
invalid ->
|
||||||
|
{error, ?ERR_BAD_REQUEST};
|
||||||
|
Fields ->
|
||||||
|
handle_adhoc_form(From, To, Request, Fields)
|
||||||
|
end;
|
||||||
|
true ->
|
||||||
|
{error, ?ERR_BAD_REQUEST}
|
||||||
|
end.
|
||||||
|
|
||||||
|
generate_adhoc_form(Lang, Node) ->
|
||||||
|
{xmlelement, "x",
|
||||||
|
[{"xmlns", ?NS_XDATA},
|
||||||
|
{"type", "form"}],
|
||||||
|
[{xmlelement, "title", [], [{xmlcdata, get_title(Lang, Node)}]}]
|
||||||
|
++
|
||||||
|
if Node == "announce/motd/delete" ->
|
||||||
|
[{xmlelement, "field",
|
||||||
|
[{"var", "confirm"},
|
||||||
|
{"type", "boolean"},
|
||||||
|
{"label", translate:translate(Lang, "Really delete message of the day?")}],
|
||||||
|
[{xmlelement, "value",
|
||||||
|
[],
|
||||||
|
[{xmlcdata, "true"}]}]}];
|
||||||
|
true ->
|
||||||
|
[{xmlelement, "field",
|
||||||
|
[{"var", "subject"},
|
||||||
|
{"type", "text-single"},
|
||||||
|
{"label", translate:translate(Lang, "Subject")}],
|
||||||
|
[]},
|
||||||
|
{xmlelement, "field",
|
||||||
|
[{"var", "body"},
|
||||||
|
{"type", "text-multi"},
|
||||||
|
{"label", translate:translate(Lang, "Message body")}],
|
||||||
|
[]}]
|
||||||
|
end}.
|
||||||
|
|
||||||
|
join_lines([]) ->
|
||||||
|
[];
|
||||||
|
join_lines(Lines) ->
|
||||||
|
join_lines(Lines, []).
|
||||||
|
join_lines([Line|Lines], Acc) ->
|
||||||
|
join_lines(Lines, ["\n",Line|Acc]);
|
||||||
|
join_lines([], Acc) ->
|
||||||
|
%% Remove last newline
|
||||||
|
lists:flatten(lists:reverse(tl(Acc))).
|
||||||
|
|
||||||
|
handle_adhoc_form(From, #jid{lserver = LServer} = To,
|
||||||
|
#adhoc_request{lang = Lang,
|
||||||
|
node = Node,
|
||||||
|
sessionid = SessionID},
|
||||||
|
Fields) ->
|
||||||
|
Confirm = case lists:keysearch("confirm", 1, Fields) of
|
||||||
|
{value, {"confirm", ["true"]}} ->
|
||||||
|
true;
|
||||||
|
{value, {"confirm", ["1"]}} ->
|
||||||
|
true;
|
||||||
|
_ ->
|
||||||
|
false
|
||||||
|
end,
|
||||||
|
Subject = case lists:keysearch("subject", 1, Fields) of
|
||||||
|
{value, {"subject", SubjectLines}} ->
|
||||||
|
%% There really shouldn't be more than one
|
||||||
|
%% subject line, but can we stop them?
|
||||||
|
join_lines(SubjectLines);
|
||||||
|
_ ->
|
||||||
|
[]
|
||||||
|
end,
|
||||||
|
Body = case lists:keysearch("body", 1, Fields) of
|
||||||
|
{value, {"body", BodyLines}} ->
|
||||||
|
join_lines(BodyLines);
|
||||||
|
_ ->
|
||||||
|
[]
|
||||||
|
end,
|
||||||
|
Response = #adhoc_response{lang = Lang,
|
||||||
|
node = Node,
|
||||||
|
sessionid = SessionID,
|
||||||
|
status = completed},
|
||||||
|
Packet = {xmlelement, "message", [{"type", "normal"}],
|
||||||
|
if Subject /= [] ->
|
||||||
|
[{xmlelement, "subject", [],
|
||||||
|
[{xmlcdata, Subject}]}];
|
||||||
|
true ->
|
||||||
|
[]
|
||||||
|
end ++
|
||||||
|
if Body /= [] ->
|
||||||
|
[{xmlelement, "body", [],
|
||||||
|
[{xmlcdata, Body}]}];
|
||||||
|
true ->
|
||||||
|
[]
|
||||||
|
end},
|
||||||
|
|
||||||
|
Proc = gen_mod:get_module_proc(LServer, ?PROCNAME),
|
||||||
|
case {Node, Body} of
|
||||||
|
{"announce/motd/delete", _} ->
|
||||||
|
if Confirm ->
|
||||||
|
Proc ! {announce_motd_delete, From, To, Packet},
|
||||||
|
adhoc:produce_response(Response);
|
||||||
|
true ->
|
||||||
|
adhoc:produce_response(Response)
|
||||||
|
end;
|
||||||
|
{_, []} ->
|
||||||
|
%% An announce message with no body is definitely an operator error.
|
||||||
|
%% Throw an error and give him/her a chance to send message again.
|
||||||
|
{error, ?ERRT_NOT_ACCEPTABLE(
|
||||||
|
Lang,
|
||||||
|
"No body provided for announce message")};
|
||||||
|
%% Now send the packet to ?PROCNAME.
|
||||||
|
%% We don't use direct announce_* functions because it
|
||||||
|
%% leads to large delay in response and <iq/> queries processing
|
||||||
|
{"announce/all", _} ->
|
||||||
|
Proc ! {announce_all, From, To, Packet},
|
||||||
|
adhoc:produce_response(Response);
|
||||||
|
{"announce/online", _} ->
|
||||||
|
Proc ! {announce_online, From, To, Packet},
|
||||||
|
adhoc:produce_response(Response);
|
||||||
|
{"announce/all-hosts/online", _} ->
|
||||||
|
Proc ! {announce_all_hosts_online, From, To, Packet},
|
||||||
|
adhoc:produce_response(Response);
|
||||||
|
{"announce/motd", _} ->
|
||||||
|
Proc ! {announce_motd, From, To, Packet},
|
||||||
|
adhoc:produce_response(Response);
|
||||||
|
{"announce/motd/update", _} ->
|
||||||
|
Proc ! {announce_motd_update, From, To, Packet},
|
||||||
|
adhoc:produce_response(Response);
|
||||||
|
_ ->
|
||||||
|
%% This can't happen, as we haven't registered any other
|
||||||
|
%% command nodes.
|
||||||
|
{error, ?ERR_INTERNAL_SERVER_ERROR}
|
||||||
|
end.
|
||||||
|
|
||||||
|
get_title(Lang, "announce") ->
|
||||||
|
translate:translate(Lang, "Announcements");
|
||||||
|
get_title(Lang, "announce/all") ->
|
||||||
|
translate:translate(Lang, "Send announcement to all users");
|
||||||
|
get_title(Lang, "announce/online") ->
|
||||||
|
translate:translate(Lang, "Send announcement to all online users");
|
||||||
|
get_title(Lang, "announce/all-hosts/online") ->
|
||||||
|
translate:translate(Lang, "Send announcement to all online users on all hosts");
|
||||||
|
get_title(Lang, "announce/motd") ->
|
||||||
|
translate:translate(Lang, "Set message of the day and send to online users");
|
||||||
|
get_title(Lang, "announce/motd/update") ->
|
||||||
|
translate:translate(Lang, "Update message of the day (don't send)");
|
||||||
|
get_title(Lang, "announce/motd/delete") ->
|
||||||
|
translate:translate(Lang, "Delete message of the day").
|
||||||
|
|
||||||
|
%-------------------------------------------------------------------------
|
||||||
|
|
||||||
announce_all(From, To, Packet) ->
|
announce_all(From, To, Packet) ->
|
||||||
Host = To#jid.lserver,
|
Host = To#jid.lserver,
|
||||||
Access = gen_mod:get_module_opt(Host, ?MODULE, access, none),
|
Access = gen_mod:get_module_opt(Host, ?MODULE, access, none),
|
||||||
case acl:match_rule(Host, Access, From) of
|
case acl:match_rule(Host, Access, From) of
|
||||||
deny ->
|
deny ->
|
||||||
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
|
Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN),
|
||||||
ejabberd_router:route(To, From, Err);
|
ejabberd_router:route(To, From, Err);
|
||||||
allow ->
|
allow ->
|
||||||
Local = jlib:make_jid("", To#jid.server, ""),
|
Local = jlib:make_jid("", To#jid.server, ""),
|
||||||
@ -126,7 +553,7 @@ announce_online(From, To, Packet) ->
|
|||||||
Access = gen_mod:get_module_opt(Host, ?MODULE, access, none),
|
Access = gen_mod:get_module_opt(Host, ?MODULE, access, none),
|
||||||
case acl:match_rule(Host, Access, From) of
|
case acl:match_rule(Host, Access, From) of
|
||||||
deny ->
|
deny ->
|
||||||
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
|
Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN),
|
||||||
ejabberd_router:route(To, From, Err);
|
ejabberd_router:route(To, From, Err);
|
||||||
allow ->
|
allow ->
|
||||||
announce_online1(ejabberd_sm:get_vh_session_list(Host),
|
announce_online1(ejabberd_sm:get_vh_session_list(Host),
|
||||||
@ -138,7 +565,7 @@ announce_all_hosts_online(From, To, Packet) ->
|
|||||||
Access = gen_mod:get_module_opt(global, ?MODULE, access, none),
|
Access = gen_mod:get_module_opt(global, ?MODULE, access, none),
|
||||||
case acl:match_rule(global, Access, From) of
|
case acl:match_rule(global, Access, From) of
|
||||||
deny ->
|
deny ->
|
||||||
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
|
Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN),
|
||||||
ejabberd_router:route(To, From, Err);
|
ejabberd_router:route(To, From, Err);
|
||||||
allow ->
|
allow ->
|
||||||
announce_online1(ejabberd_sm:dirty_get_sessions_list(),
|
announce_online1(ejabberd_sm:dirty_get_sessions_list(),
|
||||||
@ -159,7 +586,7 @@ announce_motd(From, To, Packet) ->
|
|||||||
Access = gen_mod:get_module_opt(Host, ?MODULE, access, none),
|
Access = gen_mod:get_module_opt(Host, ?MODULE, access, none),
|
||||||
case acl:match_rule(Host, Access, From) of
|
case acl:match_rule(Host, Access, From) of
|
||||||
deny ->
|
deny ->
|
||||||
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
|
Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN),
|
||||||
ejabberd_router:route(To, From, Err);
|
ejabberd_router:route(To, From, Err);
|
||||||
allow ->
|
allow ->
|
||||||
announce_motd_update(To#jid.lserver, Packet),
|
announce_motd_update(To#jid.lserver, Packet),
|
||||||
@ -179,7 +606,7 @@ announce_motd_update(From, To, Packet) ->
|
|||||||
Access = gen_mod:get_module_opt(Host, ?MODULE, access, none),
|
Access = gen_mod:get_module_opt(Host, ?MODULE, access, none),
|
||||||
case acl:match_rule(Host, Access, From) of
|
case acl:match_rule(Host, Access, From) of
|
||||||
deny ->
|
deny ->
|
||||||
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
|
Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN),
|
||||||
ejabberd_router:route(To, From, Err);
|
ejabberd_router:route(To, From, Err);
|
||||||
allow ->
|
allow ->
|
||||||
announce_motd_update(Host, Packet)
|
announce_motd_update(Host, Packet)
|
||||||
@ -197,7 +624,7 @@ announce_motd_delete(From, To, Packet) ->
|
|||||||
Access = gen_mod:get_module_opt(Host, ?MODULE, access, none),
|
Access = gen_mod:get_module_opt(Host, ?MODULE, access, none),
|
||||||
case acl:match_rule(Host, Access, From) of
|
case acl:match_rule(Host, Access, From) of
|
||||||
deny ->
|
deny ->
|
||||||
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
|
Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN),
|
||||||
ejabberd_router:route(To, From, Err);
|
ejabberd_router:route(To, From, Err);
|
||||||
allow ->
|
allow ->
|
||||||
announce_motd_delete(Host)
|
announce_motd_delete(Host)
|
||||||
@ -237,6 +664,7 @@ send_motd(#jid{luser = LUser, lserver = LServer} = JID) ->
|
|||||||
ok
|
ok
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
%-------------------------------------------------------------------------
|
||||||
|
|
||||||
update_tables() ->
|
update_tables() ->
|
||||||
update_motd_table(),
|
update_motd_table(),
|
||||||
@ -326,3 +754,4 @@ update_motd_users_table() ->
|
|||||||
?INFO_MSG("Recreating motd_users table", []),
|
?INFO_MSG("Recreating motd_users table", []),
|
||||||
mnesia:transform_table(motd_users, ignore, Fields)
|
mnesia:transform_table(motd_users, ignore, Fields)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -17,134 +17,210 @@
|
|||||||
get_local_identity/5,
|
get_local_identity/5,
|
||||||
get_local_features/5,
|
get_local_features/5,
|
||||||
get_local_items/5,
|
get_local_items/5,
|
||||||
|
adhoc_local_items/4,
|
||||||
|
adhoc_local_commands/4,
|
||||||
|
get_sm_identity/5,
|
||||||
get_sm_features/5,
|
get_sm_features/5,
|
||||||
get_sm_items/5,
|
get_sm_items/5,
|
||||||
process_local_iq/3,
|
adhoc_sm_items/4,
|
||||||
process_sm_iq/3]).
|
adhoc_sm_commands/4]).
|
||||||
|
|
||||||
-include("ejabberd.hrl").
|
-include("ejabberd.hrl").
|
||||||
-include("jlib.hrl").
|
-include("jlib.hrl").
|
||||||
|
-include("adhoc.hrl").
|
||||||
|
|
||||||
|
|
||||||
start(Host, Opts) ->
|
start(Host, _Opts) ->
|
||||||
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
|
|
||||||
gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_EJABBERD_CONFIG,
|
|
||||||
?MODULE, process_local_iq, IQDisc),
|
|
||||||
gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_EJABBERD_CONFIG,
|
|
||||||
?MODULE, process_sm_iq, IQDisc),
|
|
||||||
ejabberd_hooks:add(disco_local_items, Host, ?MODULE, get_local_items, 50),
|
ejabberd_hooks:add(disco_local_items, Host, ?MODULE, get_local_items, 50),
|
||||||
ejabberd_hooks:add(disco_local_features, Host, ?MODULE, get_local_features, 50),
|
ejabberd_hooks:add(disco_local_features, Host, ?MODULE, get_local_features, 50),
|
||||||
ejabberd_hooks:add(disco_local_identity, Host, ?MODULE, get_local_identity, 50),
|
ejabberd_hooks:add(disco_local_identity, Host, ?MODULE, get_local_identity, 50),
|
||||||
ejabberd_hooks:add(disco_sm_items, Host, ?MODULE, get_sm_items, 50),
|
ejabberd_hooks:add(disco_sm_items, Host, ?MODULE, get_sm_items, 50),
|
||||||
ejabberd_hooks:add(disco_sm_features, Host, ?MODULE, get_sm_features, 50),
|
ejabberd_hooks:add(disco_sm_features, Host, ?MODULE, get_sm_features, 50),
|
||||||
|
ejabberd_hooks:add(disco_sm_identity, Host, ?MODULE, get_sm_identity, 50),
|
||||||
|
ejabberd_hooks:add(adhoc_local_items, Host, ?MODULE, adhoc_local_items, 50),
|
||||||
|
ejabberd_hooks:add(adhoc_local_commands, Host, ?MODULE, adhoc_local_commands, 50),
|
||||||
|
ejabberd_hooks:add(adhoc_sm_items, Host, ?MODULE, adhoc_sm_items, 50),
|
||||||
|
ejabberd_hooks:add(adhoc_sm_commands, Host, ?MODULE, adhoc_sm_commands, 50),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
stop(Host) ->
|
stop(Host) ->
|
||||||
|
ejabberd_hooks:delete(adhoc_sm_commands, Host, ?MODULE, adhoc_sm_commands, 50),
|
||||||
|
ejabberd_hooks:delete(adhoc_sm_items, Host, ?MODULE, adhoc_sm_items, 50),
|
||||||
|
ejabberd_hooks:delete(adhoc_local_commands, Host, ?MODULE, adhoc_local_commands, 50),
|
||||||
|
ejabberd_hooks:delete(adhoc_local_items, Host, ?MODULE, adhoc_local_items, 50),
|
||||||
|
ejabberd_hooks:delete(disco_sm_identity, Host, ?MODULE, get_sm_identity, 50),
|
||||||
ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, get_sm_features, 50),
|
ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, get_sm_features, 50),
|
||||||
ejabberd_hooks:delete(disco_sm_items, Host, ?MODULE, get_sm_items, 50),
|
ejabberd_hooks:delete(disco_sm_items, Host, ?MODULE, get_sm_items, 50),
|
||||||
ejabberd_hooks:delete(disco_local_identity, Host, ?MODULE, get_local_identity, 50),
|
ejabberd_hooks:delete(disco_local_identity, Host, ?MODULE, get_local_identity, 50),
|
||||||
ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, get_local_features, 50),
|
ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, get_local_features, 50),
|
||||||
ejabberd_hooks:delete(disco_local_items, Host, ?MODULE, get_local_items, 50),
|
ejabberd_hooks:delete(disco_local_items, Host, ?MODULE, get_local_items, 50),
|
||||||
gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_EJABBERD_CONFIG),
|
gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_COMMANDS),
|
||||||
gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_EJABBERD_CONFIG).
|
gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_COMMANDS).
|
||||||
|
|
||||||
|
%%%-----------------------------------------------------------------------
|
||||||
|
|
||||||
-define(EMPTY_INFO_RESULT, {result, Feats}).
|
-define(INFO_IDENTITY(Category, Type, Name, Lang),
|
||||||
|
[{xmlelement, "identity",
|
||||||
|
[{"category", Category},
|
||||||
|
{"type", Type},
|
||||||
|
{"name", translate:translate(Lang, Name)}], []}]).
|
||||||
|
|
||||||
get_sm_features({error, _Error} = Acc, _From, _To, _Node, _Lang) ->
|
-define(INFO_COMMAND(Name, Lang),
|
||||||
Acc;
|
?INFO_IDENTITY("automation", "command-node", Name, Lang)).
|
||||||
|
|
||||||
|
get_sm_identity(Acc, _From, _To, Node, Lang) ->
|
||||||
|
case Node of
|
||||||
|
"config" ->
|
||||||
|
?INFO_COMMAND("Configuration", Lang);
|
||||||
|
_ ->
|
||||||
|
Acc
|
||||||
|
end.
|
||||||
|
|
||||||
|
get_local_identity(Acc, _From, _To, Node, Lang) ->
|
||||||
|
LNode = string:tokens(Node, "/"),
|
||||||
|
case LNode of
|
||||||
|
["running nodes", ENode] ->
|
||||||
|
?INFO_IDENTITY("ejabberd", "node", ENode, Lang);
|
||||||
|
["running nodes", _ENode, "DB"] ->
|
||||||
|
?INFO_COMMAND("DB", Lang);
|
||||||
|
["running nodes", _ENode, "modules", "start"] ->
|
||||||
|
?INFO_COMMAND("Start Modules", Lang);
|
||||||
|
["running nodes", _ENode, "modules", "stop"] ->
|
||||||
|
?INFO_COMMAND("Stop Modules", Lang);
|
||||||
|
["running nodes", _ENode, "backup", "backup"] ->
|
||||||
|
?INFO_COMMAND("Backup", Lang);
|
||||||
|
["running nodes", _ENode, "backup", "restore"] ->
|
||||||
|
?INFO_COMMAND("Restore", Lang);
|
||||||
|
["running nodes", _ENode, "backup", "textfile"] ->
|
||||||
|
?INFO_COMMAND("Dump to Text File", Lang);
|
||||||
|
["running nodes", _ENode, "import", "file"] ->
|
||||||
|
?INFO_COMMAND("Import File", Lang);
|
||||||
|
["running nodes", _ENode, "import", "dir"] ->
|
||||||
|
?INFO_COMMAND("Import Directory", Lang);
|
||||||
|
["config", "hostname"] ->
|
||||||
|
?INFO_COMMAND("Host Name", Lang);
|
||||||
|
["config", "acls"] ->
|
||||||
|
?INFO_COMMAND("Access Control Lists", Lang);
|
||||||
|
["config", "access"] ->
|
||||||
|
?INFO_COMMAND("Access Rules", Lang);
|
||||||
|
_ ->
|
||||||
|
Acc
|
||||||
|
end.
|
||||||
|
|
||||||
|
%%%-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
-define(INFO_RESULT(Allow, Feats),
|
||||||
|
case Allow of
|
||||||
|
deny ->
|
||||||
|
{error, ?ERR_FORBIDDEN};
|
||||||
|
allow ->
|
||||||
|
{result, Feats}
|
||||||
|
end).
|
||||||
|
|
||||||
get_sm_features(Acc, From, #jid{lserver = LServer} = _To, Node, _Lang) ->
|
get_sm_features(Acc, From, #jid{lserver = LServer} = _To, Node, _Lang) ->
|
||||||
case {acl:match_rule(LServer, configure, From), Node} of
|
case gen_mod:is_loaded(LServer, mod_adhoc) of
|
||||||
{allow, []} ->
|
false ->
|
||||||
case Acc of
|
Acc;
|
||||||
{result, Features} ->
|
|
||||||
{result, [?NS_EJABBERD_CONFIG | Features]};
|
|
||||||
empty ->
|
|
||||||
{result, [?NS_EJABBERD_CONFIG]}
|
|
||||||
end;
|
|
||||||
_ ->
|
_ ->
|
||||||
Acc
|
Allow = acl:match_rule(LServer, configure, From),
|
||||||
|
case Node of
|
||||||
|
"config" ->
|
||||||
|
?INFO_RESULT(Allow, [?NS_COMMANDS]);
|
||||||
|
_ ->
|
||||||
|
Acc
|
||||||
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
get_local_identity(Acc, _From, _To, Node, _Lang) ->
|
|
||||||
case Node of
|
|
||||||
["running nodes", ENode] ->
|
|
||||||
[{xmlelement, "identity",
|
|
||||||
[{"category", "ejabberd"},
|
|
||||||
{"type", "node"},
|
|
||||||
{"name", ENode}], []}];
|
|
||||||
_ ->
|
|
||||||
Acc
|
|
||||||
end.
|
|
||||||
|
|
||||||
get_local_features({error, _Error} = Acc, _From, _To, _Node, _Lang) ->
|
|
||||||
Acc;
|
|
||||||
|
|
||||||
get_local_features(Acc, _From, _To, [], _Lang) ->
|
|
||||||
Acc;
|
|
||||||
|
|
||||||
get_local_features(Acc, From, #jid{lserver = LServer} = _To, Node, _Lang) ->
|
get_local_features(Acc, From, #jid{lserver = LServer} = _To, Node, _Lang) ->
|
||||||
Feats = case Acc of
|
case gen_mod:is_loaded(LServer, mod_adhoc) of
|
||||||
{result, Features} -> Features;
|
false ->
|
||||||
empty -> []
|
Acc;
|
||||||
end,
|
_ ->
|
||||||
case {acl:match_rule(LServer, configure, From), Node} of
|
LNode = string:tokens(Node, "/"),
|
||||||
{deny, _} ->
|
Allow = acl:match_rule(LServer, configure, From),
|
||||||
{error, ?ERR_NOT_ALLOWED};
|
case LNode of
|
||||||
{allow, ["config"]} ->
|
["config"] ->
|
||||||
?EMPTY_INFO_RESULT;
|
?INFO_RESULT(Allow, []);
|
||||||
{allow, ["online users"]} ->
|
["online users"] ->
|
||||||
?EMPTY_INFO_RESULT;
|
?INFO_RESULT(Allow, []);
|
||||||
{allow, ["all users"]} ->
|
["all users"] ->
|
||||||
?EMPTY_INFO_RESULT;
|
?INFO_RESULT(Allow, []);
|
||||||
{allow, ["all users", [$@ | _]]} ->
|
["all users", [$@ | _]] ->
|
||||||
?EMPTY_INFO_RESULT;
|
?INFO_RESULT(Allow, []);
|
||||||
{allow, ["outgoing s2s" | _]} ->
|
["outgoing s2s" | _] ->
|
||||||
?EMPTY_INFO_RESULT;
|
?INFO_RESULT(Allow, []);
|
||||||
{allow, ["running nodes"]} ->
|
["running nodes"] ->
|
||||||
?EMPTY_INFO_RESULT;
|
?INFO_RESULT(Allow, []);
|
||||||
{allow, ["stopped nodes"]} ->
|
["stopped nodes"] ->
|
||||||
?EMPTY_INFO_RESULT;
|
?INFO_RESULT(Allow, []);
|
||||||
{allow, ["running nodes", _ENode]} ->
|
["running nodes", _ENode] ->
|
||||||
{result, [?NS_STATS | Feats]};
|
?INFO_RESULT(Allow, [?NS_STATS]);
|
||||||
{allow, ["running nodes", _ENode, "DB"]} ->
|
["running nodes", _ENode, "DB"] ->
|
||||||
{result, [?NS_EJABBERD_CONFIG | Feats]};
|
?INFO_RESULT(Allow, [?NS_COMMANDS]);
|
||||||
{allow, ["running nodes", _ENode, "modules"]} ->
|
["running nodes", _ENode, "modules"] ->
|
||||||
?EMPTY_INFO_RESULT;
|
?INFO_RESULT(Allow, []);
|
||||||
{allow, ["running nodes", _ENode, "modules", _]} ->
|
["running nodes", _ENode, "modules", _] ->
|
||||||
{result, [?NS_EJABBERD_CONFIG | Feats]};
|
?INFO_RESULT(Allow, [?NS_COMMANDS]);
|
||||||
{allow, ["running nodes", _ENode, "backup"]} ->
|
["running nodes", _ENode, "backup"] ->
|
||||||
?EMPTY_INFO_RESULT;
|
?INFO_RESULT(Allow, []);
|
||||||
{allow, ["running nodes", _ENode, "backup", _]} ->
|
["running nodes", _ENode, "backup", _] ->
|
||||||
{result, [?NS_EJABBERD_CONFIG | Feats]};
|
?INFO_RESULT(Allow, [?NS_COMMANDS]);
|
||||||
{allow, ["running nodes", _ENode, "import"]} ->
|
["running nodes", _ENode, "import"] ->
|
||||||
?EMPTY_INFO_RESULT;
|
?INFO_RESULT(Allow, []);
|
||||||
{allow, ["running nodes", _ENode, "import", _]} ->
|
["running nodes", _ENode, "import", _] ->
|
||||||
{result, [?NS_EJABBERD_CONFIG | Feats]};
|
?INFO_RESULT(Allow, [?NS_COMMANDS]);
|
||||||
{allow, ["config", _]} ->
|
["config", _] ->
|
||||||
{result, [?NS_EJABBERD_CONFIG | Feats]};
|
?INFO_RESULT(Allow, [?NS_COMMANDS]);
|
||||||
|
_ ->
|
||||||
|
Acc
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
|
%%%-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
adhoc_sm_items(Acc, From, #jid{lserver = LServer} = To, Lang) ->
|
||||||
|
case acl:match_rule(LServer, configure, From) of
|
||||||
|
allow ->
|
||||||
|
Items = case Acc of
|
||||||
|
{result, Its} -> Its;
|
||||||
|
empty -> []
|
||||||
|
end,
|
||||||
|
Nodes = [{xmlelement, "item",
|
||||||
|
[{"jid", jlib:jid_to_string(To)},
|
||||||
|
{"name", translate:translate(Lang, "Configuration")},
|
||||||
|
{"node", "config"}], []}],
|
||||||
|
{result, Items ++ Nodes};
|
||||||
_ ->
|
_ ->
|
||||||
Acc
|
Acc
|
||||||
end.
|
end.
|
||||||
|
|
||||||
get_sm_items({error, _Error} = Acc, _From, _To, _Node, _Lang) ->
|
%%%-----------------------------------------------------------------------
|
||||||
Acc;
|
|
||||||
|
|
||||||
get_sm_items(Acc, From,
|
get_sm_items(Acc, From,
|
||||||
#jid{user = User, server = Server, lserver = LServer} = _To,
|
#jid{user = User, server = Server, lserver = LServer} = To,
|
||||||
Node, _Lang) ->
|
Node, Lang) ->
|
||||||
case {acl:match_rule(LServer, configure, From), Node} of
|
case gen_mod:is_loaded(LServer, mod_adhoc) of
|
||||||
{allow, []} ->
|
false ->
|
||||||
Items = case Acc of
|
Acc;
|
||||||
{result, Its} ->
|
|
||||||
Its;
|
|
||||||
empty ->
|
|
||||||
[]
|
|
||||||
end,
|
|
||||||
{result, Items ++ get_user_resources(User, Server)};
|
|
||||||
_ ->
|
_ ->
|
||||||
Acc
|
Items = case Acc of
|
||||||
|
{result, Its} -> Its;
|
||||||
|
empty -> []
|
||||||
|
end,
|
||||||
|
case {acl:match_rule(LServer, configure, From), Node} of
|
||||||
|
{allow, ""} ->
|
||||||
|
Nodes = [{xmlelement, "item",
|
||||||
|
[{"jid", jlib:jid_to_string(To)},
|
||||||
|
{"name", translate:translate(Lang, "Configuration")},
|
||||||
|
{"node", "config"}], []}],
|
||||||
|
{result, Items ++ Nodes ++ get_user_resources(User, Server)};
|
||||||
|
{allow, "config"} ->
|
||||||
|
{result, []};
|
||||||
|
{_, "config"} ->
|
||||||
|
{error, ?ERR_FORBIDDEN};
|
||||||
|
_ ->
|
||||||
|
Acc
|
||||||
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
get_user_resources(User, Server) ->
|
get_user_resources(User, Server) ->
|
||||||
@ -155,31 +231,149 @@ get_user_resources(User, Server) ->
|
|||||||
{"name", User}], []}
|
{"name", User}], []}
|
||||||
end, lists:sort(Rs)).
|
end, lists:sort(Rs)).
|
||||||
|
|
||||||
get_local_items({error, _Error} = Acc, _From, _To, _Node, _Lang) ->
|
%%%-----------------------------------------------------------------------
|
||||||
Acc;
|
|
||||||
|
|
||||||
get_local_items(Acc, From, #jid{lserver = LServer} = To, Node, Lang) ->
|
adhoc_local_items(Acc, From, #jid{lserver = LServer, server = Server} = To,
|
||||||
Items = case Acc of
|
Lang) ->
|
||||||
{result, Its} ->
|
case acl:match_rule(LServer, configure, From) of
|
||||||
Its;
|
allow ->
|
||||||
empty ->
|
Items = case Acc of
|
||||||
|
{result, Its} -> Its;
|
||||||
|
empty -> []
|
||||||
|
end,
|
||||||
|
%% Recursively get all configure commands
|
||||||
|
Nodes = recursively_get_local_items(LServer, "", Server, Lang),
|
||||||
|
Nodes1 = lists:filter(
|
||||||
|
fun(N) ->
|
||||||
|
Nd = xml:get_tag_attr_s("node", N),
|
||||||
|
F = get_local_features([], From, To, Nd, Lang),
|
||||||
|
case F of
|
||||||
|
{result, [?NS_COMMANDS]} ->
|
||||||
|
true;
|
||||||
|
_ ->
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end, Nodes),
|
||||||
|
{result, Items ++ Nodes1};
|
||||||
|
_ ->
|
||||||
|
Acc
|
||||||
|
end.
|
||||||
|
|
||||||
|
recursively_get_local_items(_LServer, "online users", _Server, _Lang) ->
|
||||||
|
[];
|
||||||
|
|
||||||
|
recursively_get_local_items(_LServer, "all users", _Server, _Lang) ->
|
||||||
|
[];
|
||||||
|
|
||||||
|
recursively_get_local_items(LServer, Node, Server, Lang) ->
|
||||||
|
LNode = string:tokens(Node, "/"),
|
||||||
|
Items = case get_local_items(LServer, LNode, Server, Lang) of
|
||||||
|
{result, Res} ->
|
||||||
|
Res;
|
||||||
|
{error, _Error} ->
|
||||||
[]
|
[]
|
||||||
end,
|
end,
|
||||||
case acl:match_rule(LServer, configure, From) of
|
Nodes = lists:flatten(
|
||||||
deny when Node /= [] ->
|
lists:map(
|
||||||
{error, ?ERR_NOT_ALLOWED};
|
fun(N) ->
|
||||||
|
S = xml:get_tag_attr_s("jid", N),
|
||||||
|
Nd = xml:get_tag_attr_s("node", N),
|
||||||
|
if (S /= Server) or (Nd == "") ->
|
||||||
|
[];
|
||||||
|
true ->
|
||||||
|
[N, recursively_get_local_items(
|
||||||
|
LServer, Nd, Server, Lang)]
|
||||||
|
end
|
||||||
|
end, Items)),
|
||||||
|
Nodes.
|
||||||
|
|
||||||
|
%%%-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
-define(ITEMS_RESULT(Allow, LNode, Fallback),
|
||||||
|
case Allow of
|
||||||
deny ->
|
deny ->
|
||||||
{result, Items};
|
Fallback;
|
||||||
_ ->
|
allow ->
|
||||||
case get_local_items(To#jid.lserver, Node,
|
case get_local_items(LServer, LNode,
|
||||||
jlib:jid_to_string(To), Lang) of
|
jlib:jid_to_string(To), Lang) of
|
||||||
{result, Res} ->
|
{result, Res} ->
|
||||||
{result, Items ++ Res};
|
{result, Res};
|
||||||
{error, Error} ->
|
{error, Error} ->
|
||||||
{error, Error}
|
{error, Error}
|
||||||
|
end
|
||||||
|
end).
|
||||||
|
|
||||||
|
get_local_items(Acc, From, #jid{lserver = LServer} = To, "", Lang) ->
|
||||||
|
case gen_mod:is_loaded(LServer, mod_adhoc) of
|
||||||
|
false ->
|
||||||
|
Acc;
|
||||||
|
_ ->
|
||||||
|
Items = case Acc of
|
||||||
|
{result, Its} -> Its;
|
||||||
|
empty -> []
|
||||||
|
end,
|
||||||
|
Allow = acl:match_rule(LServer, configure, From),
|
||||||
|
case Allow of
|
||||||
|
deny ->
|
||||||
|
{result, Items};
|
||||||
|
allow ->
|
||||||
|
case get_local_items(LServer, [],
|
||||||
|
jlib:jid_to_string(To), Lang) of
|
||||||
|
{result, Res} ->
|
||||||
|
{result, Items ++ Res};
|
||||||
|
{error, _Error} ->
|
||||||
|
{result, Items}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
get_local_items(Acc, From, #jid{lserver = LServer} = To, Node, Lang) ->
|
||||||
|
case gen_mod:is_loaded(LServer, mod_adhoc) of
|
||||||
|
false ->
|
||||||
|
Acc;
|
||||||
|
_ ->
|
||||||
|
LNode = string:tokens(Node, "/"),
|
||||||
|
Allow = acl:match_rule(LServer, configure, From),
|
||||||
|
case LNode of
|
||||||
|
["config"] ->
|
||||||
|
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
|
||||||
|
["online users"] ->
|
||||||
|
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
|
||||||
|
["all users"] ->
|
||||||
|
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
|
||||||
|
["all users", [$@ | _]] ->
|
||||||
|
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
|
||||||
|
["outgoing s2s" | _] ->
|
||||||
|
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
|
||||||
|
["running nodes"] ->
|
||||||
|
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
|
||||||
|
["stopped nodes"] ->
|
||||||
|
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
|
||||||
|
["running nodes", _ENode] ->
|
||||||
|
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
|
||||||
|
["running nodes", _ENode, "DB"] ->
|
||||||
|
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
|
||||||
|
["running nodes", _ENode, "modules"] ->
|
||||||
|
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
|
||||||
|
["running nodes", _ENode, "modules", _] ->
|
||||||
|
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
|
||||||
|
["running nodes", _ENode, "backup"] ->
|
||||||
|
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
|
||||||
|
["running nodes", _ENode, "backup", _] ->
|
||||||
|
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
|
||||||
|
["running nodes", _ENode, "import"] ->
|
||||||
|
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
|
||||||
|
["running nodes", _ENode, "import", _] ->
|
||||||
|
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
|
||||||
|
["config", _] ->
|
||||||
|
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
|
||||||
|
_ ->
|
||||||
|
Acc
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
%%%-----------------------------------------------------------------------
|
||||||
|
|
||||||
-define(NODE(Name, Node),
|
-define(NODE(Name, Node),
|
||||||
{xmlelement, "item",
|
{xmlelement, "item",
|
||||||
[{"jid", Server},
|
[{"jid", Server},
|
||||||
@ -422,72 +616,86 @@ get_stopped_nodes(_Lang) ->
|
|||||||
end, lists:sort(DBNodes))
|
end, lists:sort(DBNodes))
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
%-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-define(COMMANDS_RESULT(Allow, From, To, Request),
|
||||||
process_local_iq(From, To, #iq{type = Type, xmlns = XMLNS,
|
case Allow of
|
||||||
lang = Lang, sub_el = SubEl} = IQ) ->
|
|
||||||
case acl:match_rule(To#jid.lserver, configure, From) of
|
|
||||||
deny ->
|
deny ->
|
||||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
|
{error, ?ERR_FORBIDDEN};
|
||||||
allow ->
|
allow ->
|
||||||
case Type of
|
adhoc_local_commands(From, To, Request)
|
||||||
set ->
|
end).
|
||||||
XDataEl = find_xdata_el(SubEl),
|
|
||||||
case XDataEl of
|
adhoc_local_commands(Acc, From, #jid{lserver = LServer} = To,
|
||||||
false ->
|
#adhoc_request{node = Node} = Request) ->
|
||||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ACCEPTABLE]};
|
LNode = string:tokens(Node, "/"),
|
||||||
{xmlelement, _Name, Attrs, _SubEls} ->
|
Allow = acl:match_rule(LServer, configure, From),
|
||||||
case xml:get_attr_s("type", Attrs) of
|
case LNode of
|
||||||
"cancel" ->
|
["running nodes", _ENode, "DB"] ->
|
||||||
IQ#iq{type = result,
|
?COMMANDS_RESULT(Allow, From, To, Request);
|
||||||
sub_el = [{xmlelement, "query",
|
["running nodes", _ENode, "modules", _] ->
|
||||||
[{"xmlns", XMLNS}], []}]};
|
?COMMANDS_RESULT(Allow, From, To, Request);
|
||||||
"submit" ->
|
["running nodes", _ENode, "backup", _] ->
|
||||||
XData = jlib:parse_xdata_submit(XDataEl),
|
?COMMANDS_RESULT(Allow, From, To, Request);
|
||||||
case XData of
|
["running nodes", _ENode, "import", _] ->
|
||||||
invalid ->
|
?COMMANDS_RESULT(Allow, From, To, Request);
|
||||||
IQ#iq{type = error,
|
["config", _] ->
|
||||||
sub_el = [SubEl, ?ERR_BAD_REQUEST]};
|
?COMMANDS_RESULT(Allow, From, To, Request);
|
||||||
_ ->
|
_ ->
|
||||||
Node =
|
Acc
|
||||||
string:tokens(
|
|
||||||
xml:get_tag_attr_s("node", SubEl),
|
|
||||||
"/"),
|
|
||||||
case set_form(Node, Lang, XData) of
|
|
||||||
{result, Res} ->
|
|
||||||
IQ#iq{type = result,
|
|
||||||
sub_el =
|
|
||||||
[{xmlelement, "query",
|
|
||||||
[{"xmlns", XMLNS}],
|
|
||||||
Res
|
|
||||||
}]};
|
|
||||||
{error, Error} ->
|
|
||||||
IQ#iq{type = error,
|
|
||||||
sub_el = [SubEl, Error]}
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
_ ->
|
|
||||||
IQ#iq{type = error,
|
|
||||||
sub_el = [SubEl, ?ERR_BAD_REQUEST]}
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
get ->
|
|
||||||
Node =
|
|
||||||
string:tokens(xml:get_tag_attr_s("node", SubEl), "/"),
|
|
||||||
case get_form(Node, Lang) of
|
|
||||||
{result, Res} ->
|
|
||||||
IQ#iq{type = result,
|
|
||||||
sub_el =
|
|
||||||
[{xmlelement, "query", [{"xmlns", XMLNS}],
|
|
||||||
Res
|
|
||||||
}]};
|
|
||||||
{error, Error} ->
|
|
||||||
IQ#iq{type = error,
|
|
||||||
sub_el = [SubEl, Error]}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
adhoc_local_commands(_From, _To,
|
||||||
|
#adhoc_request{lang = Lang,
|
||||||
|
node = Node,
|
||||||
|
sessionid = SessionID,
|
||||||
|
action = Action,
|
||||||
|
xdata = XData} = Request) ->
|
||||||
|
LNode = string:tokens(Node, "/"),
|
||||||
|
%% If the "action" attribute is not present, it is
|
||||||
|
%% understood as "execute". If there was no <actions/>
|
||||||
|
%% element in the first response (which there isn't in our
|
||||||
|
%% case), "execute" and "complete" are equivalent.
|
||||||
|
ActionIsExecute = lists:member(Action,
|
||||||
|
["", "execute", "complete"]),
|
||||||
|
if Action == "cancel" ->
|
||||||
|
%% User cancels request
|
||||||
|
adhoc:produce_response(
|
||||||
|
Request,
|
||||||
|
#adhoc_response{status = canceled});
|
||||||
|
XData == false, ActionIsExecute ->
|
||||||
|
%% User requests form
|
||||||
|
case get_form(LNode, Lang) of
|
||||||
|
{result, Form} ->
|
||||||
|
adhoc:produce_response(
|
||||||
|
Request,
|
||||||
|
#adhoc_response{status = executing,
|
||||||
|
elements = Form});
|
||||||
|
{error, Error} ->
|
||||||
|
{error, Error}
|
||||||
|
end;
|
||||||
|
XData /= false, ActionIsExecute ->
|
||||||
|
%% User returns form.
|
||||||
|
case jlib:parse_xdata_submit(XData) of
|
||||||
|
invalid ->
|
||||||
|
{error, ?ERR_BAD_REQUEST};
|
||||||
|
Fields ->
|
||||||
|
case set_form(LNode, Lang, Fields) of
|
||||||
|
{result, _Res} ->
|
||||||
|
adhoc:produce_response(
|
||||||
|
#adhoc_response{lang = Lang,
|
||||||
|
node = Node,
|
||||||
|
sessionid = SessionID,
|
||||||
|
status = completed});
|
||||||
|
{error, Error} ->
|
||||||
|
{error, Error}
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
true ->
|
||||||
|
{error, ?ERR_BAD_REQUEST}
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
-define(TLFIELD(Type, Label, Var),
|
-define(TLFIELD(Type, Label, Var),
|
||||||
{xmlelement, "field", [{"type", Type},
|
{xmlelement, "field", [{"type", Type},
|
||||||
{"label", translate:translate(Lang, Label)},
|
{"label", translate:translate(Lang, Label)},
|
||||||
@ -1107,83 +1315,60 @@ search_running_node(SNode, [Node | Nodes]) ->
|
|||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
process_sm_iq(From, To,
|
adhoc_sm_commands(_Acc, From,
|
||||||
#iq{type = Type, xmlns = XMLNS, lang = Lang, sub_el = SubEl} = IQ) ->
|
#jid{user = User, server = Server, lserver = LServer} = _To,
|
||||||
case acl:match_rule(To#jid.lserver, configure, From) of
|
#adhoc_request{lang = Lang,
|
||||||
|
node = "config",
|
||||||
|
action = Action,
|
||||||
|
xdata = XData} = Request) ->
|
||||||
|
case acl:match_rule(LServer, configure, From) of
|
||||||
deny ->
|
deny ->
|
||||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
|
{error, ?ERR_FORBIDDEN};
|
||||||
allow ->
|
allow ->
|
||||||
#jid{user = User, server = Server} = To,
|
%% If the "action" attribute is not present, it is
|
||||||
case Type of
|
%% understood as "execute". If there was no <actions/>
|
||||||
set ->
|
%% element in the first response (which there isn't in our
|
||||||
XDataEl = find_xdata_el(SubEl),
|
%% case), "execute" and "complete" are equivalent.
|
||||||
case XDataEl of
|
ActionIsExecute = lists:member(Action,
|
||||||
false ->
|
["", "execute", "complete"]),
|
||||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ACCEPTABLE]};
|
if Action == "cancel" ->
|
||||||
{xmlelement, _Name, Attrs, _SubEls} ->
|
%% User cancels request
|
||||||
case xml:get_attr_s("type", Attrs) of
|
adhoc:produce_response(
|
||||||
"cancel" ->
|
Request,
|
||||||
IQ#iq{type = result,
|
#adhoc_response{status = canceled});
|
||||||
sub_el = [{xmlelement, "query",
|
XData == false, ActionIsExecute ->
|
||||||
[{"xmlns", XMLNS}], []}]};
|
%% User requests form
|
||||||
"submit" ->
|
case get_sm_form(User, Server, "config", Lang) of
|
||||||
XData = jlib:parse_xdata_submit(XDataEl),
|
{result, Form} ->
|
||||||
case XData of
|
adhoc:produce_response(
|
||||||
invalid ->
|
Request,
|
||||||
IQ#iq{type = error,
|
#adhoc_response{status = executing,
|
||||||
sub_el = [SubEl, ?ERR_BAD_REQUEST]};
|
elements = Form});
|
||||||
_ ->
|
|
||||||
Node =
|
|
||||||
string:tokens(
|
|
||||||
xml:get_tag_attr_s("node", SubEl),
|
|
||||||
"/"),
|
|
||||||
case set_sm_form(
|
|
||||||
User, Server, Node,
|
|
||||||
Lang, XData) of
|
|
||||||
{result, Res} ->
|
|
||||||
IQ#iq{type = result,
|
|
||||||
sub_el =
|
|
||||||
[{xmlelement, "query",
|
|
||||||
[{"xmlns", XMLNS}],
|
|
||||||
Res
|
|
||||||
}]};
|
|
||||||
{error, Error} ->
|
|
||||||
IQ#iq{type = error,
|
|
||||||
sub_el = [SubEl, Error]}
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
_ ->
|
|
||||||
IQ#iq{type = error,
|
|
||||||
sub_el = [SubEl, ?ERR_BAD_REQUEST]}
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
get ->
|
|
||||||
Node =
|
|
||||||
string:tokens(xml:get_tag_attr_s("node", SubEl), "/"),
|
|
||||||
case get_sm_form(User, Server, Node, Lang) of
|
|
||||||
{result, Res} ->
|
|
||||||
IQ#iq{type = result,
|
|
||||||
sub_el =
|
|
||||||
[{xmlelement, "query", [{"xmlns", XMLNS}],
|
|
||||||
Res
|
|
||||||
}]};
|
|
||||||
{error, Error} ->
|
{error, Error} ->
|
||||||
IQ#iq{type = error, sub_el = [SubEl, Error]}
|
{error, Error}
|
||||||
end
|
end;
|
||||||
|
XData /= false, ActionIsExecute ->
|
||||||
|
%% User returns form.
|
||||||
|
case jlib:parse_xdata_submit(XData) of
|
||||||
|
invalid ->
|
||||||
|
{error, ?ERR_BAD_REQUEST};
|
||||||
|
Fields ->
|
||||||
|
set_sm_form(User, Server, "config", Request, Fields)
|
||||||
|
end;
|
||||||
|
true ->
|
||||||
|
{error, ?ERR_BAD_REQUEST}
|
||||||
end
|
end
|
||||||
end.
|
end;
|
||||||
|
|
||||||
|
adhoc_sm_commands(Acc, _From, _To, _Request) ->
|
||||||
|
Acc.
|
||||||
|
|
||||||
get_sm_form(User, Server, [], Lang) ->
|
get_sm_form(User, Server, "config", Lang) ->
|
||||||
{result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}],
|
{result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}],
|
||||||
[{xmlelement, "title", [],
|
[{xmlelement, "title", [],
|
||||||
[{xmlcdata,
|
[{xmlcdata,
|
||||||
translate:translate(
|
translate:translate(
|
||||||
Lang, "Administration of ") ++ User}]},
|
Lang, "Administration of ") ++ User}]},
|
||||||
%{xmlelement, "instructions", [],
|
|
||||||
% [{xmlcdata,
|
|
||||||
% translate:translate(
|
|
||||||
% Lang, "Choose host name")}]},
|
|
||||||
{xmlelement, "field",
|
{xmlelement, "field",
|
||||||
[{"type", "list-single"},
|
[{"type", "list-single"},
|
||||||
{"label", translate:translate(Lang, "Action on user")},
|
{"label", translate:translate(Lang, "Action on user")},
|
||||||
@ -1198,49 +1383,36 @@ get_sm_form(User, Server, [], Lang) ->
|
|||||||
]},
|
]},
|
||||||
?XFIELD("text-private", "Password", "password",
|
?XFIELD("text-private", "Password", "password",
|
||||||
ejabberd_auth:get_password_s(User, Server))
|
ejabberd_auth:get_password_s(User, Server))
|
||||||
%{xmlelement, "field", [{"type", "text-single"},
|
|
||||||
% {"label",
|
|
||||||
% translate:translate(Lang, "Host name")},
|
|
||||||
% {"var", "hostname"}],
|
|
||||||
% [{xmlelement, "value", [], [{xmlcdata, ?MYNAME}]}]}
|
|
||||||
]}]};
|
]}]};
|
||||||
|
|
||||||
get_sm_form(_User, _Server, _Node, _Lang) ->
|
get_sm_form(_User, _Server, _Node, _Lang) ->
|
||||||
{error, ?ERR_SERVICE_UNAVAILABLE}.
|
{error, ?ERR_SERVICE_UNAVAILABLE}.
|
||||||
|
|
||||||
|
|
||||||
set_sm_form(User, Server, [], _Lang, XData) ->
|
set_sm_form(User, Server, "config",
|
||||||
|
#adhoc_request{lang = Lang,
|
||||||
|
node = Node,
|
||||||
|
sessionid = SessionID}, XData) ->
|
||||||
|
Response = #adhoc_response{lang = Lang,
|
||||||
|
node = Node,
|
||||||
|
sessionid = SessionID,
|
||||||
|
status = completed},
|
||||||
case lists:keysearch("action", 1, XData) of
|
case lists:keysearch("action", 1, XData) of
|
||||||
{value, {_, ["edit"]}} ->
|
{value, {_, ["edit"]}} ->
|
||||||
case lists:keysearch("password", 1, XData) of
|
case lists:keysearch("password", 1, XData) of
|
||||||
{value, {_, [Password]}} ->
|
{value, {_, [Password]}} ->
|
||||||
ejabberd_auth:set_password(User, Server, Password),
|
ejabberd_auth:set_password(User, Server, Password),
|
||||||
{result, []};
|
adhoc:produce_response(Response);
|
||||||
_ ->
|
_ ->
|
||||||
{error, ?ERR_BAD_REQUEST}
|
{error, ?ERR_NOT_ACCEPTABLE}
|
||||||
end;
|
end;
|
||||||
{value, {_, ["remove"]}} ->
|
{value, {_, ["remove"]}} ->
|
||||||
catch ejabberd_auth:remove_user(User, Server),
|
catch ejabberd_auth:remove_user(User, Server),
|
||||||
{result, []};
|
adhoc:produce_response(Response);
|
||||||
_ ->
|
_ ->
|
||||||
{error, ?ERR_BAD_REQUEST}
|
{error, ?ERR_NOT_ACCEPTABLE}
|
||||||
end;
|
end;
|
||||||
set_sm_form(_User, _Server, _Node, _Lang, _XData) ->
|
|
||||||
|
set_sm_form(_User, _Server, _Node, _Request, _Fields) ->
|
||||||
{error, ?ERR_SERVICE_UNAVAILABLE}.
|
{error, ?ERR_SERVICE_UNAVAILABLE}.
|
||||||
|
|
||||||
find_xdata_el({xmlelement, _Name, _Attrs, SubEls}) ->
|
|
||||||
find_xdata_el1(SubEls).
|
|
||||||
|
|
||||||
find_xdata_el1([]) ->
|
|
||||||
false;
|
|
||||||
|
|
||||||
find_xdata_el1([{xmlelement, Name, Attrs, SubEls} | Els]) ->
|
|
||||||
case xml:get_attr_s("xmlns", Attrs) of
|
|
||||||
?NS_XDATA ->
|
|
||||||
{xmlelement, Name, Attrs, SubEls};
|
|
||||||
_ ->
|
|
||||||
find_xdata_el1(Els)
|
|
||||||
end;
|
|
||||||
|
|
||||||
find_xdata_el1([_ | Els]) ->
|
|
||||||
find_xdata_el1(Els).
|
|
||||||
|
@ -113,8 +113,7 @@ process_local_iq_items(From, To, #iq{type = Type, lang = Lang, sub_el = SubEl} =
|
|||||||
set ->
|
set ->
|
||||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
|
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
|
||||||
get ->
|
get ->
|
||||||
SNode = xml:get_tag_attr_s("node", SubEl),
|
Node = xml:get_tag_attr_s("node", SubEl),
|
||||||
Node = string:tokens(SNode, "/"),
|
|
||||||
Host = To#jid.lserver,
|
Host = To#jid.lserver,
|
||||||
|
|
||||||
case ejabberd_hooks:run_fold(disco_local_items,
|
case ejabberd_hooks:run_fold(disco_local_items,
|
||||||
@ -123,8 +122,8 @@ process_local_iq_items(From, To, #iq{type = Type, lang = Lang, sub_el = SubEl} =
|
|||||||
[From, To, Node, Lang]) of
|
[From, To, Node, Lang]) of
|
||||||
{result, Items} ->
|
{result, Items} ->
|
||||||
ANode = case Node of
|
ANode = case Node of
|
||||||
[] -> [];
|
"" -> [];
|
||||||
_ -> [{"node", SNode}]
|
_ -> [{"node", Node}]
|
||||||
end,
|
end,
|
||||||
IQ#iq{type = result,
|
IQ#iq{type = result,
|
||||||
sub_el = [{xmlelement, "query",
|
sub_el = [{xmlelement, "query",
|
||||||
@ -144,8 +143,7 @@ process_local_iq_info(From, To, #iq{type = Type, lang = Lang,
|
|||||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
|
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
|
||||||
get ->
|
get ->
|
||||||
Host = To#jid.lserver,
|
Host = To#jid.lserver,
|
||||||
SNode = xml:get_tag_attr_s("node", SubEl),
|
Node = xml:get_tag_attr_s("node", SubEl),
|
||||||
Node = string:tokens(SNode, "/"),
|
|
||||||
Identity = ejabberd_hooks:run_fold(disco_local_identity,
|
Identity = ejabberd_hooks:run_fold(disco_local_identity,
|
||||||
Host,
|
Host,
|
||||||
[],
|
[],
|
||||||
@ -156,8 +154,8 @@ process_local_iq_info(From, To, #iq{type = Type, lang = Lang,
|
|||||||
[From, To, Node, Lang]) of
|
[From, To, Node, Lang]) of
|
||||||
{result, Features} ->
|
{result, Features} ->
|
||||||
ANode = case Node of
|
ANode = case Node of
|
||||||
[] -> [];
|
"" -> [];
|
||||||
_ -> [{"node", SNode}]
|
_ -> [{"node", Node}]
|
||||||
end,
|
end,
|
||||||
IQ#iq{type = result,
|
IQ#iq{type = result,
|
||||||
sub_el = [{xmlelement, "query",
|
sub_el = [{xmlelement, "query",
|
||||||
@ -252,7 +250,7 @@ get_vh_services(Host) ->
|
|||||||
process_sm_iq_items(From, To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) ->
|
process_sm_iq_items(From, To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) ->
|
||||||
case Type of
|
case Type of
|
||||||
set ->
|
set ->
|
||||||
#jid{user = User, luser = LTo, lserver = ToServer} = To,
|
#jid{luser = LTo, lserver = ToServer} = To,
|
||||||
#jid{luser = LFrom, lserver = LServer} = From,
|
#jid{luser = LFrom, lserver = LServer} = From,
|
||||||
Self = (LTo == LFrom) andalso (ToServer == LServer),
|
Self = (LTo == LFrom) andalso (ToServer == LServer),
|
||||||
Node = xml:get_tag_attr_s("node", SubEl),
|
Node = xml:get_tag_attr_s("node", SubEl),
|
||||||
@ -272,16 +270,15 @@ process_sm_iq_items(From, To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ
|
|||||||
end;
|
end;
|
||||||
get ->
|
get ->
|
||||||
Host = To#jid.lserver,
|
Host = To#jid.lserver,
|
||||||
SNode = xml:get_tag_attr_s("node", SubEl),
|
Node = xml:get_tag_attr_s("node", SubEl),
|
||||||
Node = string:tokens(SNode, "/"),
|
|
||||||
case ejabberd_hooks:run_fold(disco_sm_items,
|
case ejabberd_hooks:run_fold(disco_sm_items,
|
||||||
Host,
|
Host,
|
||||||
empty,
|
empty,
|
||||||
[From, To, Node, Lang]) of
|
[From, To, Node, Lang]) of
|
||||||
{result, Items} ->
|
{result, Items} ->
|
||||||
ANode = case Node of
|
ANode = case Node of
|
||||||
[] -> [];
|
"" -> [];
|
||||||
_ -> [{"node", SNode}]
|
_ -> [{"node", Node}]
|
||||||
end,
|
end,
|
||||||
IQ#iq{type = result,
|
IQ#iq{type = result,
|
||||||
sub_el = [{xmlelement, "query",
|
sub_el = [{xmlelement, "query",
|
||||||
@ -329,8 +326,7 @@ process_sm_iq_info(From, To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ)
|
|||||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
|
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
|
||||||
get ->
|
get ->
|
||||||
Host = To#jid.lserver,
|
Host = To#jid.lserver,
|
||||||
SNode = xml:get_tag_attr_s("node", SubEl),
|
Node = xml:get_tag_attr_s("node", SubEl),
|
||||||
Node = string:tokens(SNode, "/"),
|
|
||||||
Identity = ejabberd_hooks:run_fold(disco_sm_identity,
|
Identity = ejabberd_hooks:run_fold(disco_sm_identity,
|
||||||
Host,
|
Host,
|
||||||
[],
|
[],
|
||||||
@ -341,8 +337,8 @@ process_sm_iq_info(From, To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ)
|
|||||||
[From, To, Node, Lang]) of
|
[From, To, Node, Lang]) of
|
||||||
{result, Features} ->
|
{result, Features} ->
|
||||||
ANode = case Node of
|
ANode = case Node of
|
||||||
[] -> [];
|
"" -> [];
|
||||||
_ -> [{"node", SNode}]
|
_ -> [{"node", Node}]
|
||||||
end,
|
end,
|
||||||
IQ#iq{type = result,
|
IQ#iq{type = result,
|
||||||
sub_el = [{xmlelement, "query",
|
sub_el = [{xmlelement, "query",
|
||||||
@ -384,24 +380,17 @@ get_user_resources(User, Server) ->
|
|||||||
|
|
||||||
get_publish_items(empty,
|
get_publish_items(empty,
|
||||||
#jid{luser = LFrom, lserver = LSFrom},
|
#jid{luser = LFrom, lserver = LSFrom},
|
||||||
#jid{user = User, server = Server, luser = LTo, lserver = LSTo} = _To,
|
#jid{luser = LTo, lserver = LSTo} = _To,
|
||||||
Node, _Lang) ->
|
Node, _Lang) ->
|
||||||
if
|
if
|
||||||
(LFrom == LTo) and (LSFrom == LSTo) ->
|
(LFrom == LTo) and (LSFrom == LSTo) ->
|
||||||
% Hack
|
retrieve_disco_publish({LTo, LSTo}, Node);
|
||||||
SNode = join(Node, "/"),
|
|
||||||
retrieve_disco_publish({LTo, LSTo}, SNode);
|
|
||||||
true ->
|
true ->
|
||||||
empty
|
empty
|
||||||
end;
|
end;
|
||||||
get_publish_items(Acc, _From, _To, _Node, _Lang) ->
|
get_publish_items(Acc, _From, _To, _Node, _Lang) ->
|
||||||
Acc.
|
Acc.
|
||||||
|
|
||||||
join(List, Sep) ->
|
|
||||||
lists:foldl(fun(A, "") -> A;
|
|
||||||
(A, Acc) -> Acc ++ Sep ++ A
|
|
||||||
end, "", List).
|
|
||||||
|
|
||||||
process_disco_publish(User, Node, Items) ->
|
process_disco_publish(User, Node, Items) ->
|
||||||
F = fun() ->
|
F = fun() ->
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
|
@ -107,7 +107,7 @@ do_route1(Host, ServerHost, Access, From, To, Packet) ->
|
|||||||
"iq" ->
|
"iq" ->
|
||||||
case jlib:iq_query_info(Packet) of
|
case jlib:iq_query_info(Packet) of
|
||||||
#iq{type = get, xmlns = ?NS_DISCO_INFO = XMLNS,
|
#iq{type = get, xmlns = ?NS_DISCO_INFO = XMLNS,
|
||||||
sub_el = SubEl} = IQ ->
|
sub_el = _SubEl} = IQ ->
|
||||||
Res = IQ#iq{type = result,
|
Res = IQ#iq{type = result,
|
||||||
sub_el = [{xmlelement, "query",
|
sub_el = [{xmlelement, "query",
|
||||||
[{"xmlns", XMLNS}],
|
[{"xmlns", XMLNS}],
|
||||||
@ -123,7 +123,7 @@ do_route1(Host, ServerHost, Access, From, To, Packet) ->
|
|||||||
#iq{type = get,
|
#iq{type = get,
|
||||||
xmlns = ?NS_REGISTER = XMLNS,
|
xmlns = ?NS_REGISTER = XMLNS,
|
||||||
lang = Lang,
|
lang = Lang,
|
||||||
sub_el = SubEl} = IQ ->
|
sub_el = _SubEl} = IQ ->
|
||||||
Res = IQ#iq{type = result,
|
Res = IQ#iq{type = result,
|
||||||
sub_el =
|
sub_el =
|
||||||
[{xmlelement, "query",
|
[{xmlelement, "query",
|
||||||
@ -155,7 +155,7 @@ do_route1(Host, ServerHost, Access, From, To, Packet) ->
|
|||||||
#iq{type = get,
|
#iq{type = get,
|
||||||
xmlns = ?NS_VCARD = XMLNS,
|
xmlns = ?NS_VCARD = XMLNS,
|
||||||
lang = Lang,
|
lang = Lang,
|
||||||
sub_el = SubEl} = IQ ->
|
sub_el = _SubEl} = IQ ->
|
||||||
Res = IQ#iq{type = result,
|
Res = IQ#iq{type = result,
|
||||||
sub_el =
|
sub_el =
|
||||||
[{xmlelement, "vCard",
|
[{xmlelement, "vCard",
|
||||||
@ -380,76 +380,81 @@ iq_get_register_info(Host, From, Lang) ->
|
|||||||
Lang, "Enter nickname you want to register")}]},
|
Lang, "Enter nickname you want to register")}]},
|
||||||
?XFIELD("text-single", "Nickname", "nick", Nick)]}].
|
?XFIELD("text-single", "Nickname", "nick", Nick)]}].
|
||||||
|
|
||||||
iq_set_register_info(Host, From, XData, Lang) ->
|
iq_set_register_info(Host, From, Nick, Lang) ->
|
||||||
{LUser, LServer, _} = jlib:jid_tolower(From),
|
{LUser, LServer, _} = jlib:jid_tolower(From),
|
||||||
LUS = {LUser, LServer},
|
LUS = {LUser, LServer},
|
||||||
case lists:keysearch("nick", 1, XData) of
|
F = fun() ->
|
||||||
false ->
|
case Nick of
|
||||||
ErrText = "You must fill in field \"nick\" in the form",
|
"" ->
|
||||||
{error, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)};
|
mnesia:delete({muc_registered, {LUS, Host}}),
|
||||||
{value, {_, [Nick]}} ->
|
ok;
|
||||||
F = fun() ->
|
_ ->
|
||||||
case Nick of
|
Allow =
|
||||||
"" ->
|
case mnesia:select(
|
||||||
mnesia:delete({muc_registered, {LUS, Host}}),
|
muc_registered,
|
||||||
|
[{#muc_registered{us_host = '$1',
|
||||||
|
nick = Nick,
|
||||||
|
_ = '_'},
|
||||||
|
[{'==', {element, 2, '$1'}, Host}],
|
||||||
|
['$_']}]) of
|
||||||
|
[] ->
|
||||||
|
true;
|
||||||
|
[#muc_registered{us_host = {U, _Host}}] ->
|
||||||
|
U == LUS
|
||||||
|
end,
|
||||||
|
if
|
||||||
|
Allow ->
|
||||||
|
mnesia:write(
|
||||||
|
#muc_registered{us_host = {LUS, Host},
|
||||||
|
nick = Nick}),
|
||||||
ok;
|
ok;
|
||||||
_ ->
|
true ->
|
||||||
Allow =
|
false
|
||||||
case mnesia:select(
|
|
||||||
muc_registered,
|
|
||||||
[{#muc_registered{us_host = '$1',
|
|
||||||
nick = Nick,
|
|
||||||
_ = '_'},
|
|
||||||
[{'==', {element, 2, '$1'}, Host}],
|
|
||||||
['$_']}]) of
|
|
||||||
[] ->
|
|
||||||
true;
|
|
||||||
[#muc_registered{us_host = {U, _Host}}] ->
|
|
||||||
U == LUS
|
|
||||||
end,
|
|
||||||
if
|
|
||||||
Allow ->
|
|
||||||
mnesia:write(
|
|
||||||
#muc_registered{us_host = {LUS, Host},
|
|
||||||
nick = Nick}),
|
|
||||||
ok;
|
|
||||||
true ->
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end,
|
end
|
||||||
case mnesia:transaction(F) of
|
end,
|
||||||
{atomic, ok} ->
|
case mnesia:transaction(F) of
|
||||||
{result, []};
|
{atomic, ok} ->
|
||||||
{atomic, false} ->
|
{result, []};
|
||||||
ErrText = "Specified nickname is already registered",
|
{atomic, false} ->
|
||||||
{error, ?ERRT_CONFLICT(Lang, ErrText)};
|
ErrText = "Specified nickname is already registered",
|
||||||
_ ->
|
{error, ?ERRT_CONFLICT(Lang, ErrText)};
|
||||||
{error, ?ERR_INTERNAL_SERVER_ERROR}
|
_ ->
|
||||||
end
|
{error, ?ERR_INTERNAL_SERVER_ERROR}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
process_iq_register_set(Host, From, SubEl, Lang) ->
|
process_iq_register_set(Host, From, SubEl, Lang) ->
|
||||||
{xmlelement, _Name, _Attrs, Els} = SubEl,
|
{xmlelement, _Name, _Attrs, Els} = SubEl,
|
||||||
case xml:remove_cdata(Els) of
|
case xml:get_subtag(SubEl, "remove") of
|
||||||
[{xmlelement, "x", _Attrs1, _Els1} = XEl] ->
|
false ->
|
||||||
case {xml:get_tag_attr_s("xmlns", XEl),
|
case xml:remove_cdata(Els) of
|
||||||
xml:get_tag_attr_s("type", XEl)} of
|
[{xmlelement, "x", _Attrs1, _Els1} = XEl] ->
|
||||||
{?NS_XDATA, "cancel"} ->
|
case {xml:get_tag_attr_s("xmlns", XEl),
|
||||||
{result, []};
|
xml:get_tag_attr_s("type", XEl)} of
|
||||||
{?NS_XDATA, "submit"} ->
|
{?NS_XDATA, "cancel"} ->
|
||||||
XData = jlib:parse_xdata_submit(XEl),
|
{result, []};
|
||||||
case XData of
|
{?NS_XDATA, "submit"} ->
|
||||||
invalid ->
|
XData = jlib:parse_xdata_submit(XEl),
|
||||||
{error, ?ERR_BAD_REQUEST};
|
case XData of
|
||||||
|
invalid ->
|
||||||
|
{error, ?ERR_BAD_REQUEST};
|
||||||
|
_ ->
|
||||||
|
case lists:keysearch("nick", 1, XData) of
|
||||||
|
false ->
|
||||||
|
ErrText = "You must fill in field \"Nickname\" in the form",
|
||||||
|
{error, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)};
|
||||||
|
{value, {_, [Nick]}} ->
|
||||||
|
iq_set_register_info(Host, From, Nick, Lang)
|
||||||
|
end
|
||||||
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
iq_set_register_info(Host, From, XData, Lang)
|
{error, ?ERR_BAD_REQUEST}
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
{error, ?ERR_BAD_REQUEST}
|
{error, ?ERR_BAD_REQUEST}
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
{error, ?ERR_BAD_REQUEST}
|
iq_set_register_info(Host, From, "", Lang)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
iq_get_vcard(Lang) ->
|
iq_get_vcard(Lang) ->
|
||||||
|
@ -101,7 +101,7 @@ start(Host, ServerHost, Access, Room, Opts) ->
|
|||||||
%% ignore |
|
%% ignore |
|
||||||
%% {stop, StopReason}
|
%% {stop, StopReason}
|
||||||
%%----------------------------------------------------------------------
|
%%----------------------------------------------------------------------
|
||||||
init([Host, ServerHost, Access, Room, Creator, Nick]) ->
|
init([Host, ServerHost, Access, Room, Creator, _Nick]) ->
|
||||||
State = set_affiliation(Creator, owner,
|
State = set_affiliation(Creator, owner,
|
||||||
#state{host = Host,
|
#state{host = Host,
|
||||||
server_host = ServerHost,
|
server_host = ServerHost,
|
||||||
@ -559,16 +559,11 @@ normal_state({route, From, ToNick,
|
|||||||
end,
|
end,
|
||||||
{next_state, normal_state, StateData};
|
{next_state, normal_state, StateData};
|
||||||
|
|
||||||
normal_state(Event, StateData) ->
|
normal_state(_Event, StateData) ->
|
||||||
{next_state, normal_state, StateData}.
|
{next_state, normal_state, StateData}.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
%%----------------------------------------------------------------------
|
||||||
%% Func: handle_event/3
|
%% Func: handle_event/3
|
||||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
%% Returns: {next_state, NextStateName, NextStateData} |
|
||||||
@ -862,15 +857,13 @@ filter_presence({xmlelement, "presence", Attrs, Els}) ->
|
|||||||
case El of
|
case El of
|
||||||
{xmlcdata, _} ->
|
{xmlcdata, _} ->
|
||||||
false;
|
false;
|
||||||
{xmlelement, Name1, Attrs1, _Els1} ->
|
{xmlelement, _Name1, Attrs1, _Els1} ->
|
||||||
XMLNS = xml:get_attr_s("xmlns", Attrs1),
|
XMLNS = xml:get_attr_s("xmlns", Attrs1),
|
||||||
case {Name1, XMLNS} of
|
case XMLNS of
|
||||||
{"show", ""} ->
|
?NS_MUC ++ _ ->
|
||||||
true;
|
false;
|
||||||
{"status", ""} ->
|
|
||||||
true;
|
|
||||||
_ ->
|
_ ->
|
||||||
false
|
true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end, Els),
|
end, Els),
|
||||||
@ -971,6 +964,20 @@ add_new_user(From, Nick, {xmlelement, _, Attrs, Els} = Packet, StateData) ->
|
|||||||
add_user_presence(
|
add_user_presence(
|
||||||
From, Packet,
|
From, Packet,
|
||||||
add_online_user(From, Nick, Role, StateData)),
|
add_online_user(From, Nick, Role, StateData)),
|
||||||
|
if not (NewState#state.config)#config.anonymous ->
|
||||||
|
WPacket = {xmlelement, "message", [{"type", "groupchat"}],
|
||||||
|
[{xmlelement, "body", [],
|
||||||
|
[{xmlcdata, translate:translate(
|
||||||
|
Lang,
|
||||||
|
"This room is not anonymous")}]},
|
||||||
|
{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}],
|
||||||
|
[{xmlelement, "status", [{"code", "100"}], []}]}]},
|
||||||
|
ejabberd_router:route(
|
||||||
|
StateData#state.jid,
|
||||||
|
From, WPacket);
|
||||||
|
true ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
send_new_presence(From, NewState),
|
send_new_presence(From, NewState),
|
||||||
send_existing_presences(From, NewState),
|
send_existing_presences(From, NewState),
|
||||||
Shift = count_stanza_shift(Nick, Els, NewState),
|
Shift = count_stanza_shift(Nick, Els, NewState),
|
||||||
@ -1550,23 +1557,23 @@ process_admin_items_set(UJID, Items, Lang, StateData) ->
|
|||||||
set_affiliation_and_reason(
|
set_affiliation_and_reason(
|
||||||
JID, outcast, Reason,
|
JID, outcast, Reason,
|
||||||
set_role(JID, none, SD));
|
set_role(JID, none, SD));
|
||||||
{JID, affiliation, A, Reason} when
|
{JID, affiliation, A, _Reason} when
|
||||||
(A == admin) or (A == owner) ->
|
(A == admin) or (A == owner) ->
|
||||||
SD1 = set_affiliation(JID, A, SD),
|
SD1 = set_affiliation(JID, A, SD),
|
||||||
SD2 = set_role(JID, moderator, SD1),
|
SD2 = set_role(JID, moderator, SD1),
|
||||||
send_update_presence(JID, SD2),
|
send_update_presence(JID, SD2),
|
||||||
SD2;
|
SD2;
|
||||||
{JID, affiliation, member, Reason} ->
|
{JID, affiliation, member, _Reason} ->
|
||||||
SD1 = set_affiliation(
|
SD1 = set_affiliation(
|
||||||
JID, member, SD),
|
JID, member, SD),
|
||||||
SD2 = set_role(JID, participant, SD1),
|
SD2 = set_role(JID, participant, SD1),
|
||||||
send_update_presence(JID, SD2),
|
send_update_presence(JID, SD2),
|
||||||
SD2;
|
SD2;
|
||||||
{JID, role, R, Reason} ->
|
{JID, role, R, _Reason} ->
|
||||||
SD1 = set_role(JID, R, SD),
|
SD1 = set_role(JID, R, SD),
|
||||||
catch send_new_presence(JID, SD1),
|
catch send_new_presence(JID, SD1),
|
||||||
SD1;
|
SD1;
|
||||||
{JID, affiliation, A, Reason} ->
|
{JID, affiliation, A, _Reason} ->
|
||||||
SD1 = set_affiliation(JID, A, SD),
|
SD1 = set_affiliation(JID, A, SD),
|
||||||
send_update_presence(JID, SD1),
|
send_update_presence(JID, SD1),
|
||||||
SD1
|
SD1
|
||||||
@ -1593,7 +1600,7 @@ process_admin_items_set(UJID, Items, Lang, StateData) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
find_changed_items(UJID, UAffiliation, URole, [], _Lang, StateData, Res) ->
|
find_changed_items(_UJID, _UAffiliation, _URole, [], _Lang, _StateData, Res) ->
|
||||||
{result, Res};
|
{result, Res};
|
||||||
find_changed_items(UJID, UAffiliation, URole, [{xmlcdata, _} | Items],
|
find_changed_items(UJID, UAffiliation, URole, [{xmlcdata, _} | Items],
|
||||||
Lang, StateData, Res) ->
|
Lang, StateData, Res) ->
|
||||||
@ -1721,143 +1728,143 @@ find_changed_items(_UJID, _UAffiliation, _URole, _Items,
|
|||||||
{error, ?ERR_BAD_REQUEST}.
|
{error, ?ERR_BAD_REQUEST}.
|
||||||
|
|
||||||
|
|
||||||
can_change_ra(FAffiliation, FRole,
|
can_change_ra(_FAffiliation, _FRole,
|
||||||
TAffiliation, TRole,
|
TAffiliation, _TRole,
|
||||||
affiliation, Value)
|
affiliation, Value)
|
||||||
when (TAffiliation == Value) ->
|
when (TAffiliation == Value) ->
|
||||||
nothing;
|
nothing;
|
||||||
can_change_ra(FAffiliation, FRole,
|
can_change_ra(_FAffiliation, _FRole,
|
||||||
TAffiliation, TRole,
|
_TAffiliation, TRole,
|
||||||
role, Value)
|
role, Value)
|
||||||
when (TRole == Value) ->
|
when (TRole == Value) ->
|
||||||
nothing;
|
nothing;
|
||||||
can_change_ra(FAffiliation, FRole,
|
can_change_ra(FAffiliation, _FRole,
|
||||||
outcast, TRole,
|
outcast, _TRole,
|
||||||
affiliation, none)
|
affiliation, none)
|
||||||
when (FAffiliation == owner) or (FAffiliation == admin) ->
|
when (FAffiliation == owner) or (FAffiliation == admin) ->
|
||||||
true;
|
true;
|
||||||
can_change_ra(FAffiliation, FRole,
|
can_change_ra(FAffiliation, _FRole,
|
||||||
outcast, TRole,
|
outcast, _TRole,
|
||||||
affiliation, member)
|
affiliation, member)
|
||||||
when (FAffiliation == owner) or (FAffiliation == admin) ->
|
when (FAffiliation == owner) or (FAffiliation == admin) ->
|
||||||
true;
|
true;
|
||||||
can_change_ra(owner, FRole,
|
can_change_ra(owner, _FRole,
|
||||||
outcast, TRole,
|
outcast, _TRole,
|
||||||
affiliation, admin) ->
|
affiliation, admin) ->
|
||||||
true;
|
true;
|
||||||
can_change_ra(owner, FRole,
|
can_change_ra(owner, _FRole,
|
||||||
outcast, TRole,
|
outcast, _TRole,
|
||||||
affiliation, owner) ->
|
affiliation, owner) ->
|
||||||
true;
|
true;
|
||||||
can_change_ra(FAffiliation, FRole,
|
can_change_ra(FAffiliation, _FRole,
|
||||||
none, TRole,
|
none, _TRole,
|
||||||
affiliation, outcast)
|
affiliation, outcast)
|
||||||
when (FAffiliation == owner) or (FAffiliation == admin) ->
|
when (FAffiliation == owner) or (FAffiliation == admin) ->
|
||||||
true;
|
true;
|
||||||
can_change_ra(FAffiliation, FRole,
|
can_change_ra(FAffiliation, _FRole,
|
||||||
none, TRole,
|
none, _TRole,
|
||||||
affiliation, member)
|
affiliation, member)
|
||||||
when (FAffiliation == owner) or (FAffiliation == admin) ->
|
when (FAffiliation == owner) or (FAffiliation == admin) ->
|
||||||
true;
|
true;
|
||||||
can_change_ra(owner, FRole,
|
can_change_ra(owner, _FRole,
|
||||||
none, TRole,
|
none, _TRole,
|
||||||
affiliation, admin) ->
|
affiliation, admin) ->
|
||||||
true;
|
true;
|
||||||
can_change_ra(owner, FRole,
|
can_change_ra(owner, _FRole,
|
||||||
none, TRole,
|
none, _TRole,
|
||||||
affiliation, owner) ->
|
affiliation, owner) ->
|
||||||
true;
|
true;
|
||||||
can_change_ra(FAffiliation, FRole,
|
can_change_ra(FAffiliation, _FRole,
|
||||||
member, TRole,
|
member, _TRole,
|
||||||
affiliation, outcast)
|
affiliation, outcast)
|
||||||
when (FAffiliation == owner) or (FAffiliation == admin) ->
|
when (FAffiliation == owner) or (FAffiliation == admin) ->
|
||||||
true;
|
true;
|
||||||
can_change_ra(FAffiliation, FRole,
|
can_change_ra(FAffiliation, _FRole,
|
||||||
member, TRole,
|
member, _TRole,
|
||||||
affiliation, none)
|
affiliation, none)
|
||||||
when (FAffiliation == owner) or (FAffiliation == admin) ->
|
when (FAffiliation == owner) or (FAffiliation == admin) ->
|
||||||
true;
|
true;
|
||||||
can_change_ra(owner, FRole,
|
can_change_ra(owner, _FRole,
|
||||||
member, TRole,
|
member, _TRole,
|
||||||
affiliation, admin) ->
|
affiliation, admin) ->
|
||||||
true;
|
true;
|
||||||
can_change_ra(owner, FRole,
|
can_change_ra(owner, _FRole,
|
||||||
member, TRole,
|
member, _TRole,
|
||||||
affiliation, owner) ->
|
affiliation, owner) ->
|
||||||
true;
|
true;
|
||||||
can_change_ra(owner, FRole,
|
can_change_ra(owner, _FRole,
|
||||||
admin, TRole,
|
admin, _TRole,
|
||||||
affiliation, _Affiliation) ->
|
affiliation, _Affiliation) ->
|
||||||
true;
|
true;
|
||||||
can_change_ra(owner, FRole,
|
can_change_ra(owner, _FRole,
|
||||||
owner, TRole,
|
owner, _TRole,
|
||||||
affiliation, _Affiliation) ->
|
affiliation, _Affiliation) ->
|
||||||
true;
|
true;
|
||||||
can_change_ra(FAffiliation, FRole,
|
can_change_ra(_FAffiliation, _FRole,
|
||||||
TAffiliation, TRole,
|
_TAffiliation, _TRole,
|
||||||
affiliation, Value) ->
|
affiliation, _Value) ->
|
||||||
false;
|
false;
|
||||||
can_change_ra(FAffiliation, moderator,
|
can_change_ra(_FAffiliation, moderator,
|
||||||
TAffiliation, visitor,
|
_TAffiliation, visitor,
|
||||||
role, none) ->
|
role, none) ->
|
||||||
true;
|
true;
|
||||||
can_change_ra(FAffiliation, moderator,
|
can_change_ra(_FAffiliation, moderator,
|
||||||
TAffiliation, visitor,
|
_TAffiliation, visitor,
|
||||||
role, participant) ->
|
role, participant) ->
|
||||||
true;
|
true;
|
||||||
can_change_ra(FAffiliation, FRole,
|
can_change_ra(FAffiliation, _FRole,
|
||||||
TAffiliation, visitor,
|
_TAffiliation, visitor,
|
||||||
role, moderator)
|
role, moderator)
|
||||||
when (FAffiliation == owner) or (FAffiliation == admin) ->
|
when (FAffiliation == owner) or (FAffiliation == admin) ->
|
||||||
true;
|
true;
|
||||||
can_change_ra(FAffiliation, moderator,
|
can_change_ra(_FAffiliation, moderator,
|
||||||
TAffiliation, participant,
|
_TAffiliation, participant,
|
||||||
role, none) ->
|
role, none) ->
|
||||||
true;
|
true;
|
||||||
can_change_ra(FAffiliation, moderator,
|
can_change_ra(_FAffiliation, moderator,
|
||||||
TAffiliation, participant,
|
_TAffiliation, participant,
|
||||||
role, visitor) ->
|
role, visitor) ->
|
||||||
true;
|
true;
|
||||||
can_change_ra(FAffiliation, FRole,
|
can_change_ra(FAffiliation, _FRole,
|
||||||
TAffiliation, participant,
|
_TAffiliation, participant,
|
||||||
role, moderator)
|
role, moderator)
|
||||||
when (FAffiliation == owner) or (FAffiliation == admin) ->
|
when (FAffiliation == owner) or (FAffiliation == admin) ->
|
||||||
true;
|
true;
|
||||||
can_change_ra(FAffiliation, FRole,
|
can_change_ra(_FAffiliation, _FRole,
|
||||||
owner, moderator,
|
owner, moderator,
|
||||||
role, visitor) ->
|
role, visitor) ->
|
||||||
false;
|
false;
|
||||||
can_change_ra(owner, FRole,
|
can_change_ra(owner, _FRole,
|
||||||
TAffiliation, moderator,
|
_TAffiliation, moderator,
|
||||||
role, visitor) ->
|
role, visitor) ->
|
||||||
true;
|
true;
|
||||||
can_change_ra(FAffiliation, FRole,
|
can_change_ra(_FAffiliation, _FRole,
|
||||||
admin, moderator,
|
admin, moderator,
|
||||||
role, visitor) ->
|
role, visitor) ->
|
||||||
false;
|
false;
|
||||||
can_change_ra(admin, FRole,
|
can_change_ra(admin, _FRole,
|
||||||
TAffiliation, moderator,
|
_TAffiliation, moderator,
|
||||||
role, visitor) ->
|
role, visitor) ->
|
||||||
true;
|
true;
|
||||||
can_change_ra(FAffiliation, FRole,
|
can_change_ra(_FAffiliation, _FRole,
|
||||||
owner, moderator,
|
owner, moderator,
|
||||||
role, participant) ->
|
role, participant) ->
|
||||||
false;
|
false;
|
||||||
can_change_ra(owner, FRole,
|
can_change_ra(owner, _FRole,
|
||||||
TAffiliation, moderator,
|
_TAffiliation, moderator,
|
||||||
role, participant) ->
|
role, participant) ->
|
||||||
true;
|
true;
|
||||||
can_change_ra(FAffiliation, FRole,
|
can_change_ra(_FAffiliation, _FRole,
|
||||||
admin, moderator,
|
admin, moderator,
|
||||||
role, participant) ->
|
role, participant) ->
|
||||||
false;
|
false;
|
||||||
can_change_ra(admin, FRole,
|
can_change_ra(admin, _FRole,
|
||||||
TAffiliation, moderator,
|
_TAffiliation, moderator,
|
||||||
role, participant) ->
|
role, participant) ->
|
||||||
true;
|
true;
|
||||||
can_change_ra(FAffiliation, FRole,
|
can_change_ra(_FAffiliation, _FRole,
|
||||||
TAffiliation, TRole,
|
_TAffiliation, _TRole,
|
||||||
role, Value) ->
|
role, _Value) ->
|
||||||
false.
|
false.
|
||||||
|
|
||||||
|
|
||||||
@ -1887,13 +1894,13 @@ send_kickban_presence(JID, Reason, Code, StateData) ->
|
|||||||
end, LJIDs).
|
end, LJIDs).
|
||||||
|
|
||||||
send_kickban_presence1(UJID, Reason, Code, StateData) ->
|
send_kickban_presence1(UJID, Reason, Code, StateData) ->
|
||||||
{ok, #user{jid = RealJID,
|
{ok, #user{jid = _RealJID,
|
||||||
nick = Nick}} =
|
nick = Nick}} =
|
||||||
?DICT:find(jlib:jid_tolower(UJID), StateData#state.users),
|
?DICT:find(jlib:jid_tolower(UJID), StateData#state.users),
|
||||||
Affiliation = get_affiliation(UJID, StateData),
|
Affiliation = get_affiliation(UJID, StateData),
|
||||||
SAffiliation = affiliation_to_list(Affiliation),
|
SAffiliation = affiliation_to_list(Affiliation),
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun({LJID, Info}) ->
|
fun({_LJID, Info}) ->
|
||||||
ItemAttrs = [{"affiliation", SAffiliation},
|
ItemAttrs = [{"affiliation", SAffiliation},
|
||||||
{"role", "none"}],
|
{"role", "none"}],
|
||||||
ItemEls = case Reason of
|
ItemEls = case Reason of
|
||||||
@ -1922,9 +1929,9 @@ process_iq_owner(From, set, Lang, SubEl, StateData) ->
|
|||||||
FAffiliation = get_affiliation(From, StateData),
|
FAffiliation = get_affiliation(From, StateData),
|
||||||
case FAffiliation of
|
case FAffiliation of
|
||||||
owner ->
|
owner ->
|
||||||
{xmlelement, Name, Attrs, Els} = SubEl,
|
{xmlelement, _Name, _Attrs, Els} = SubEl,
|
||||||
case xml:remove_cdata(Els) of
|
case xml:remove_cdata(Els) of
|
||||||
[{xmlelement, "x", Attrs1, Els1} = XEl] ->
|
[{xmlelement, "x", _Attrs1, _Els1} = XEl] ->
|
||||||
case {xml:get_tag_attr_s("xmlns", XEl),
|
case {xml:get_tag_attr_s("xmlns", XEl),
|
||||||
xml:get_tag_attr_s("type", XEl)} of
|
xml:get_tag_attr_s("type", XEl)} of
|
||||||
{?NS_XDATA, "cancel"} ->
|
{?NS_XDATA, "cancel"} ->
|
||||||
@ -1934,8 +1941,8 @@ process_iq_owner(From, set, Lang, SubEl, StateData) ->
|
|||||||
_ ->
|
_ ->
|
||||||
{error, ?ERR_BAD_REQUEST}
|
{error, ?ERR_BAD_REQUEST}
|
||||||
end;
|
end;
|
||||||
[{xmlelement, "destroy", Attrs1, Els1}] ->
|
[{xmlelement, "destroy", _Attrs1, _Els1} = SubEl1] ->
|
||||||
destroy_room(Els1, StateData);
|
destroy_room(SubEl1, StateData);
|
||||||
Items ->
|
Items ->
|
||||||
process_admin_items_set(From, Items, Lang, StateData)
|
process_admin_items_set(From, Items, Lang, StateData)
|
||||||
end;
|
end;
|
||||||
@ -1948,7 +1955,7 @@ process_iq_owner(From, get, Lang, SubEl, StateData) ->
|
|||||||
FAffiliation = get_affiliation(From, StateData),
|
FAffiliation = get_affiliation(From, StateData),
|
||||||
case FAffiliation of
|
case FAffiliation of
|
||||||
owner ->
|
owner ->
|
||||||
{xmlelement, Name, Attrs, Els} = SubEl,
|
{xmlelement, _Name, _Attrs, Els} = SubEl,
|
||||||
case xml:remove_cdata(Els) of
|
case xml:remove_cdata(Els) of
|
||||||
[] ->
|
[] ->
|
||||||
get_config(Lang, StateData);
|
get_config(Lang, StateData);
|
||||||
@ -2009,39 +2016,18 @@ get_config(Lang, StateData) ->
|
|||||||
[{xmlcdata, translate:translate(Lang, "Configuration for ") ++
|
[{xmlcdata, translate:translate(Lang, "Configuration for ") ++
|
||||||
jlib:jid_to_string(StateData#state.jid)}]},
|
jlib:jid_to_string(StateData#state.jid)}]},
|
||||||
?STRINGXFIELD("Room title",
|
?STRINGXFIELD("Room title",
|
||||||
"title",
|
"title",
|
||||||
Config#config.title),
|
Config#config.title),
|
||||||
?BOOLXFIELD("Allow users to change subject?",
|
?BOOLXFIELD("Make room persistent",
|
||||||
"allow_change_subj",
|
|
||||||
Config#config.allow_change_subj),
|
|
||||||
?BOOLXFIELD("Allow users to query other users?",
|
|
||||||
"allow_query_users",
|
|
||||||
Config#config.allow_query_users),
|
|
||||||
?BOOLXFIELD("Allow users to send private messages?",
|
|
||||||
"allow_private_messages",
|
|
||||||
Config#config.allow_private_messages),
|
|
||||||
?BOOLXFIELD("Make room public searchable?",
|
|
||||||
"public",
|
|
||||||
Config#config.public),
|
|
||||||
?BOOLXFIELD("Make participants list public?",
|
|
||||||
"public_list",
|
|
||||||
Config#config.public_list),
|
|
||||||
?BOOLXFIELD("Make room persistent?",
|
|
||||||
"persistent",
|
"persistent",
|
||||||
Config#config.persistent),
|
Config#config.persistent),
|
||||||
?BOOLXFIELD("Make room moderated?",
|
?BOOLXFIELD("Make room public searchable",
|
||||||
"moderated",
|
"public",
|
||||||
Config#config.moderated),
|
Config#config.public),
|
||||||
?BOOLXFIELD("Default users as members?",
|
?BOOLXFIELD("Make participants list public",
|
||||||
"members_by_default",
|
"public_list",
|
||||||
Config#config.members_by_default),
|
Config#config.public_list),
|
||||||
?BOOLXFIELD("Make room members only?",
|
?BOOLXFIELD("Make room password protected",
|
||||||
"members_only",
|
|
||||||
Config#config.members_only),
|
|
||||||
?BOOLXFIELD("Allow users to send invites?",
|
|
||||||
"allow_user_invites",
|
|
||||||
Config#config.allow_user_invites),
|
|
||||||
?BOOLXFIELD("Make room password protected?",
|
|
||||||
"password_protected",
|
"password_protected",
|
||||||
Config#config.password_protected),
|
Config#config.password_protected),
|
||||||
?PRIVATEXFIELD("Password",
|
?PRIVATEXFIELD("Password",
|
||||||
@ -2050,10 +2036,31 @@ get_config(Lang, StateData) ->
|
|||||||
true -> Config#config.password;
|
true -> Config#config.password;
|
||||||
false -> ""
|
false -> ""
|
||||||
end),
|
end),
|
||||||
?BOOLXFIELD("Make room anonymous?",
|
?BOOLXFIELD("Make room semianonymous",
|
||||||
"anonymous",
|
"anonymous",
|
||||||
Config#config.anonymous),
|
Config#config.anonymous),
|
||||||
?BOOLXFIELD("Enable logging?",
|
?BOOLXFIELD("Make room members-only",
|
||||||
|
"members_only",
|
||||||
|
Config#config.members_only),
|
||||||
|
?BOOLXFIELD("Make room moderated",
|
||||||
|
"moderated",
|
||||||
|
Config#config.moderated),
|
||||||
|
?BOOLXFIELD("Default users as participants",
|
||||||
|
"members_by_default",
|
||||||
|
Config#config.members_by_default),
|
||||||
|
?BOOLXFIELD("Allow users to change subject",
|
||||||
|
"allow_change_subj",
|
||||||
|
Config#config.allow_change_subj),
|
||||||
|
?BOOLXFIELD("Allow users to send private messages",
|
||||||
|
"allow_private_messages",
|
||||||
|
Config#config.allow_private_messages),
|
||||||
|
?BOOLXFIELD("Allow users to query other users",
|
||||||
|
"allow_query_users",
|
||||||
|
Config#config.allow_query_users),
|
||||||
|
?BOOLXFIELD("Allow users to send invites",
|
||||||
|
"allow_user_invites",
|
||||||
|
Config#config.allow_user_invites),
|
||||||
|
?BOOLXFIELD("Enable logging",
|
||||||
"logging",
|
"logging",
|
||||||
Config#config.logging)
|
Config#config.logging)
|
||||||
],
|
],
|
||||||
@ -2125,7 +2132,7 @@ set_xoption([{"anonymous", [Val]} | Opts], Config) ->
|
|||||||
?SET_BOOL_XOPT(anonymous, Val);
|
?SET_BOOL_XOPT(anonymous, Val);
|
||||||
set_xoption([{"logging", [Val]} | Opts], Config) ->
|
set_xoption([{"logging", [Val]} | Opts], Config) ->
|
||||||
?SET_BOOL_XOPT(logging, Val);
|
?SET_BOOL_XOPT(logging, Val);
|
||||||
set_xoption([_ | Opts], Config) ->
|
set_xoption([_ | _Opts], _Config) ->
|
||||||
{error, ?ERR_BAD_REQUEST}.
|
{error, ?ERR_BAD_REQUEST}.
|
||||||
|
|
||||||
|
|
||||||
@ -2203,17 +2210,15 @@ make_opts(StateData) ->
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
destroy_room(DEls, StateData) ->
|
destroy_room(DEl, StateData) ->
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun({LJID, Info}) ->
|
fun({_LJID, Info}) ->
|
||||||
Nick = Info#user.nick,
|
Nick = Info#user.nick,
|
||||||
ItemAttrs = [{"affiliation", "none"},
|
ItemAttrs = [{"affiliation", "none"},
|
||||||
{"role", "none"}],
|
{"role", "none"}],
|
||||||
Packet = {xmlelement, "presence", [{"type", "unavailable"}],
|
Packet = {xmlelement, "presence", [{"type", "unavailable"}],
|
||||||
[{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}],
|
[{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}],
|
||||||
[{xmlelement, "item", ItemAttrs, []},
|
[{xmlelement, "item", ItemAttrs, []}, DEl]}]},
|
||||||
{xmlelement, "destroy", [],
|
|
||||||
DEls}]}]},
|
|
||||||
ejabberd_router:route(
|
ejabberd_router:route(
|
||||||
jlib:jid_replace_resource(StateData#state.jid, Nick),
|
jlib:jid_replace_resource(StateData#state.jid, Nick),
|
||||||
Info#user.jid,
|
Info#user.jid,
|
||||||
@ -2243,10 +2248,10 @@ destroy_room(DEls, StateData) ->
|
|||||||
?FEATURE(Fiffalse)
|
?FEATURE(Fiffalse)
|
||||||
end).
|
end).
|
||||||
|
|
||||||
process_iq_disco_info(From, set, Lang, StateData) ->
|
process_iq_disco_info(_From, set, _Lang, _StateData) ->
|
||||||
{error, ?ERR_NOT_ALLOWED};
|
{error, ?ERR_NOT_ALLOWED};
|
||||||
|
|
||||||
process_iq_disco_info(From, get, Lang, StateData) ->
|
process_iq_disco_info(_From, get, Lang, StateData) ->
|
||||||
Config = StateData#state.config,
|
Config = StateData#state.config,
|
||||||
{result, [{xmlelement, "identity",
|
{result, [{xmlelement, "identity",
|
||||||
[{"category", "conference"},
|
[{"category", "conference"},
|
||||||
@ -2266,13 +2271,33 @@ process_iq_disco_info(From, get, Lang, StateData) ->
|
|||||||
"muc_moderated", "muc_unmoderated"),
|
"muc_moderated", "muc_unmoderated"),
|
||||||
?CONFIG_OPT_TO_FEATURE(Config#config.password_protected,
|
?CONFIG_OPT_TO_FEATURE(Config#config.password_protected,
|
||||||
"muc_passwordprotected", "muc_unsecured")
|
"muc_passwordprotected", "muc_unsecured")
|
||||||
], StateData}.
|
] ++ iq_disco_info_extras(Lang, StateData), StateData}.
|
||||||
|
|
||||||
|
-define(RFIELDT(Type, Var, Val),
|
||||||
|
{xmlelement, "field", [{"type", Type}, {"var", Var}],
|
||||||
|
[{xmlelement, "value", [], [{xmlcdata, Val}]}]}).
|
||||||
|
|
||||||
process_iq_disco_items(From, set, Lang, StateData) ->
|
-define(RFIELD(Label, Var, Val),
|
||||||
|
{xmlelement, "field", [{"label", translate:translate(Lang, Label)},
|
||||||
|
{"var", Var}],
|
||||||
|
[{xmlelement, "value", [], [{xmlcdata, Val}]}]}).
|
||||||
|
|
||||||
|
iq_disco_info_extras(Lang, StateData) ->
|
||||||
|
Len = length(?DICT:to_list(StateData#state.users)),
|
||||||
|
[{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "result"}],
|
||||||
|
[?RFIELDT("hidden", "FORM_TYPE",
|
||||||
|
"http://jabber.org/protocol/muc#roominfo"),
|
||||||
|
?RFIELD("Description", "muc#roominfo_description",
|
||||||
|
(StateData#state.config)#config.title),
|
||||||
|
%?RFIELD("Subject", "muc#roominfo_subject", StateData#state.subject),
|
||||||
|
?RFIELD("Number of occupants", "muc#roominfo_occupants",
|
||||||
|
integer_to_list(Len))
|
||||||
|
]}].
|
||||||
|
|
||||||
|
process_iq_disco_items(_From, set, _Lang, _StateData) ->
|
||||||
{error, ?ERR_NOT_ALLOWED};
|
{error, ?ERR_NOT_ALLOWED};
|
||||||
|
|
||||||
process_iq_disco_items(From, get, Lang, StateData) ->
|
process_iq_disco_items(From, get, _Lang, StateData) ->
|
||||||
FAffiliation = get_affiliation(From, StateData),
|
FAffiliation = get_affiliation(From, StateData),
|
||||||
FRole = get_role(From, StateData),
|
FRole = get_role(From, StateData),
|
||||||
case ((StateData#state.config)#config.public_list == true) orelse
|
case ((StateData#state.config)#config.public_list == true) orelse
|
||||||
@ -2282,7 +2307,7 @@ process_iq_disco_items(From, get, Lang, StateData) ->
|
|||||||
true ->
|
true ->
|
||||||
UList =
|
UList =
|
||||||
lists:map(
|
lists:map(
|
||||||
fun({LJID, Info}) ->
|
fun({_LJID, Info}) ->
|
||||||
Nick = Info#user.nick,
|
Nick = Info#user.nick,
|
||||||
{xmlelement, "item",
|
{xmlelement, "item",
|
||||||
[{"jid", jlib:jid_to_string(
|
[{"jid", jlib:jid_to_string(
|
||||||
@ -2314,11 +2339,11 @@ check_invitation(From, Els, StateData) ->
|
|||||||
CanInvite = (StateData#state.config)#config.allow_user_invites
|
CanInvite = (StateData#state.config)#config.allow_user_invites
|
||||||
orelse (FAffiliation == admin) orelse (FAffiliation == owner),
|
orelse (FAffiliation == admin) orelse (FAffiliation == owner),
|
||||||
case xml:remove_cdata(Els) of
|
case xml:remove_cdata(Els) of
|
||||||
[{xmlelement, "x", Attrs1, Els1} = XEl] ->
|
[{xmlelement, "x", _Attrs1, Els1} = XEl] ->
|
||||||
case xml:get_tag_attr_s("xmlns", XEl) of
|
case xml:get_tag_attr_s("xmlns", XEl) of
|
||||||
?NS_MUC_USER ->
|
?NS_MUC_USER ->
|
||||||
case xml:remove_cdata(Els1) of
|
case xml:remove_cdata(Els1) of
|
||||||
[{xmlelement, "invite", Attrs2, Els2} = InviteEl] ->
|
[{xmlelement, "invite", Attrs2, _Els2} = InviteEl] ->
|
||||||
case jlib:string_to_jid(
|
case jlib:string_to_jid(
|
||||||
xml:get_attr_s("to", Attrs2)) of
|
xml:get_attr_s("to", Attrs2)) of
|
||||||
error ->
|
error ->
|
||||||
|
Loading…
Reference in New Issue
Block a user