mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-20 16:15:59 +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
|
||||
escaped in like queries. MySQL where not escaping those escaped
|
||||
|
@ -23,7 +23,7 @@ endif
|
||||
|
||||
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
|
||||
SOURCES = $(wildcard *.erl)
|
||||
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_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_ARG_WITH(erlang,
|
||||
[ --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>
|
||||
#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=''
|
||||
|
||||
# Initialize some variables set by options.
|
||||
@ -850,6 +850,7 @@ Optional Features:
|
||||
--enable-web enable web (default: yes)
|
||||
--enable-tls enable tls (default: yes)
|
||||
--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
|
||||
|
||||
Optional Packages:
|
||||
@ -858,6 +859,7 @@ Optional Packages:
|
||||
--with-erlang=PREFIX path to erlc and erl
|
||||
--with-libiconv-prefix=PREFIX prefix where libiconv 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
|
||||
|
||||
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.
|
||||
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.
|
||||
if test "${enable_roster_gateway_workaround+set}" = set; then
|
||||
enableval="$enable_roster_gateway_workaround"
|
||||
@ -4239,7 +4516,7 @@ else
|
||||
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
|
||||
|
||||
@ -5056,6 +5333,7 @@ do
|
||||
"stringprep/Makefile" ) CONFIG_FILES="$CONFIG_FILES stringprep/Makefile" ;;
|
||||
"$make_tls" ) CONFIG_FILES="$CONFIG_FILES $make_tls" ;;
|
||||
"$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: error: invalid argument: $ac_config_target" >&2;}
|
||||
{ (exit 1); exit 1; }; };;
|
||||
@ -5158,6 +5436,8 @@ s,@CPP@,$CPP,;t t
|
||||
s,@EGREP@,$EGREP,;t t
|
||||
s,@EXPAT_CFLAGS@,$EXPAT_CFLAGS,;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,@mod_pubsub@,$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,@odbc@,$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,@SSL_LIBS@,$SSL_LIBS,;t t
|
||||
s,@SSL_CFLAGS@,$SSL_CFLAGS,;t t
|
||||
|
@ -14,6 +14,8 @@ AM_WITH_ERLANG
|
||||
AM_ICONV
|
||||
#locating libexpat
|
||||
AM_WITH_EXPAT
|
||||
#locating zlib
|
||||
AM_WITH_ZLIB
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
@ -29,6 +31,7 @@ AC_MOD_ENABLE(eldap, yes)
|
||||
AC_MOD_ENABLE(web, yes)
|
||||
AC_MOD_ENABLE(tls, yes)
|
||||
AC_MOD_ENABLE(odbc, no)
|
||||
AC_MOD_ENABLE(ejabberd_zlib, yes)
|
||||
|
||||
AC_ARG_ENABLE(roster_gateway_workaround,
|
||||
[ --enable-roster-gateway-workaround Turn on workaround for processing gateway subscriptions],
|
||||
@ -47,7 +50,8 @@ AC_CONFIG_FILES([Makefile
|
||||
$make_web
|
||||
stringprep/Makefile
|
||||
$make_tls
|
||||
$make_odbc])
|
||||
$make_odbc
|
||||
$make_ejabberd_zlib])
|
||||
#openssl
|
||||
AM_WITH_OPENSSL
|
||||
AC_OUTPUT
|
||||
|
@ -134,13 +134,14 @@
|
||||
{mod_register, [{access, register}]},
|
||||
{mod_roster, []},
|
||||
{mod_privacy, []},
|
||||
{mod_configure, []},
|
||||
{mod_adhoc, []},
|
||||
{mod_configure, []}, % Depends on mod_adhoc
|
||||
{mod_configure2, []},
|
||||
{mod_disco, []},
|
||||
{mod_stats, []},
|
||||
{mod_vcard, []},
|
||||
{mod_offline, []},
|
||||
{mod_announce, [{access, announce}]},
|
||||
{mod_announce, [{access, announce}]}, % Depends on mod_adhoc
|
||||
{mod_echo, [{host, "echo.localhost"}]},
|
||||
{mod_private, []},
|
||||
{mod_irc, []},
|
||||
|
@ -46,6 +46,7 @@
|
||||
sasl_state,
|
||||
access,
|
||||
shaper,
|
||||
zlib = false,
|
||||
tls = false,
|
||||
tls_required = false,
|
||||
tls_enabled = false,
|
||||
@ -125,6 +126,7 @@ init([{SockMod, Socket}, Opts]) ->
|
||||
{value, {_, S}} -> S;
|
||||
_ -> none
|
||||
end,
|
||||
Zlib = lists:member(zlib, Opts),
|
||||
StartTLS = lists:member(starttls, Opts),
|
||||
StartTLSRequired = lists:member(starttls_required, Opts),
|
||||
TLSEnabled = lists:member(tls, Opts),
|
||||
@ -145,6 +147,7 @@ init([{SockMod, Socket}, Opts]) ->
|
||||
{ok, wait_for_stream, #state{socket = Socket1,
|
||||
sockmod = SockMod1,
|
||||
receiver = ReceiverPid,
|
||||
zlib = Zlib,
|
||||
tls = TLS,
|
||||
tls_required = StartTLSRequired,
|
||||
tls_enabled = TLSEnabled,
|
||||
@ -200,10 +203,22 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
||||
{xmlelement, "mechanism", [],
|
||||
[{xmlcdata, S}]}
|
||||
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,
|
||||
TLSEnabled = StateData#state.tls_enabled,
|
||||
TLSRequired = StateData#state.tls_required,
|
||||
SockMod = StateData#state.sockmod,
|
||||
TLSFeature =
|
||||
case (TLS == true) andalso
|
||||
(TLSEnabled == false) andalso
|
||||
@ -224,7 +239,7 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
||||
end,
|
||||
send_element(StateData,
|
||||
{xmlelement, "stream:features", [],
|
||||
TLSFeature ++
|
||||
TLSFeature ++ CompressFeature ++
|
||||
[{xmlelement, "mechanisms",
|
||||
[{"xmlns", ?NS_SASL}],
|
||||
Mechs}] ++
|
||||
@ -337,7 +352,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
|
||||
end,
|
||||
send_element(StateData, Res),
|
||||
{next_state, wait_for_auth, StateData};
|
||||
{auth, _ID, set, {U, P, D, ""}} ->
|
||||
{auth, _ID, set, {_U, _P, _D, ""}} ->
|
||||
Err = jlib:make_error_reply(
|
||||
El,
|
||||
?ERR_AUTH_NO_RESOURCE_PROVIDED(StateData#state.lang)),
|
||||
@ -434,6 +449,7 @@ wait_for_auth(closed, StateData) ->
|
||||
|
||||
wait_for_feature_request({xmlstreamelement, El}, StateData) ->
|
||||
{xmlelement, Name, Attrs, Els} = El,
|
||||
Zlib = StateData#state.zlib,
|
||||
TLS = StateData#state.tls,
|
||||
TLSEnabled = StateData#state.tls_enabled,
|
||||
TLSRequired = StateData#state.tls_required,
|
||||
@ -497,6 +513,19 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) ->
|
||||
streamid = new_id(),
|
||||
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
|
||||
(SockMod == gen_tcp) and TLSRequired ->
|
||||
|
@ -17,6 +17,7 @@
|
||||
change_shaper/2,
|
||||
reset_stream/1,
|
||||
starttls/2,
|
||||
compress/2,
|
||||
become_controller/1,
|
||||
close/1]).
|
||||
|
||||
@ -54,6 +55,9 @@ reset_stream(Pid) ->
|
||||
starttls(Pid, TLSSocket) ->
|
||||
gen_server:call(Pid, {starttls, TLSSocket}).
|
||||
|
||||
compress(Pid, ZlibSocket) ->
|
||||
gen_server:call(Pid, {compress, ZlibSocket}).
|
||||
|
||||
become_controller(Pid) ->
|
||||
gen_server:call(Pid, become_controller).
|
||||
|
||||
@ -110,6 +114,20 @@ handle_call({starttls, TLSSocket}, _From,
|
||||
{error, _Reason} ->
|
||||
{stop, normal, ok, NewState}
|
||||
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,
|
||||
#state{xml_stream_state = XMLStreamState,
|
||||
c2s_pid = C2SPid} = State) ->
|
||||
@ -157,6 +175,13 @@ handle_info({Tag, _TCPSocket, Data},
|
||||
{error, _Reason} ->
|
||||
{stop, normal, State}
|
||||
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)}
|
||||
end;
|
||||
@ -211,7 +236,6 @@ activate_socket(#state{socket = Socket,
|
||||
SockMod:setopts(Socket, [{active, once}])
|
||||
end.
|
||||
|
||||
|
||||
process_data(Data,
|
||||
#state{xml_stream_state = XMLStreamState,
|
||||
shaper_state = ShaperState} = State) ->
|
||||
|
@ -179,7 +179,7 @@ wait_for_handshake({xmlstreamelement, El}, StateData) ->
|
||||
end, StateData#state.hosts),
|
||||
{next_state, stream_established, StateData};
|
||||
_ ->
|
||||
send_text(StateData, ?INVALID_HEADER_ERR),
|
||||
send_text(StateData, ?INVALID_HANDSHAKE_ERR),
|
||||
{stop, normal, StateData}
|
||||
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_with_opts/1,
|
||||
get_hosts/2,
|
||||
get_module_proc/2]).
|
||||
get_module_proc/2,
|
||||
is_loaded/2]).
|
||||
|
||||
-export([behaviour_info/1]).
|
||||
|
||||
@ -144,3 +145,6 @@ get_hosts(Opts, Prefix) ->
|
||||
get_module_proc(Host, Base) ->
|
||||
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_OWNER, "http://jabber.org/protocol/pubsub#owner").
|
||||
-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").
|
||||
|
||||
@ -48,6 +49,9 @@
|
||||
|
||||
-define(NS_FEATURE_IQAUTH, "http://jabber.org/features/iq-auth").
|
||||
-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)
|
||||
-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,
|
||||
stop/1,
|
||||
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("jlib.hrl").
|
||||
-include("adhoc.hrl").
|
||||
|
||||
-record(motd, {server, packet}).
|
||||
-record(motd_users, {us, dummy = []}).
|
||||
@ -33,6 +39,11 @@ start(Host, _Opts) ->
|
||||
update_tables(),
|
||||
ejabberd_hooks:add(local_send_to_resource_hook, Host,
|
||||
?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,
|
||||
?MODULE, send_motd, 50),
|
||||
register(gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||
@ -66,6 +77,11 @@ loop() ->
|
||||
end.
|
||||
|
||||
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,
|
||||
?MODULE, announce, 50),
|
||||
ejabberd_hooks:delete(sm_register_connection_hook, Host,
|
||||
@ -74,6 +90,7 @@ stop(Host) ->
|
||||
exit(whereis(Proc), stop),
|
||||
{wait, Proc}.
|
||||
|
||||
% Announcing via messages to a custom resource
|
||||
announce(From, To, Packet) ->
|
||||
case To of
|
||||
#jid{luser = "", lresource = Res} ->
|
||||
@ -105,12 +122,422 @@ announce(From, To, Packet) ->
|
||||
ok
|
||||
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) ->
|
||||
Host = To#jid.lserver,
|
||||
Access = gen_mod:get_module_opt(Host, ?MODULE, access, none),
|
||||
case acl:match_rule(Host, Access, From) of
|
||||
deny ->
|
||||
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
|
||||
Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN),
|
||||
ejabberd_router:route(To, From, Err);
|
||||
allow ->
|
||||
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),
|
||||
case acl:match_rule(Host, Access, From) of
|
||||
deny ->
|
||||
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
|
||||
Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN),
|
||||
ejabberd_router:route(To, From, Err);
|
||||
allow ->
|
||||
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),
|
||||
case acl:match_rule(global, Access, From) of
|
||||
deny ->
|
||||
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
|
||||
Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN),
|
||||
ejabberd_router:route(To, From, Err);
|
||||
allow ->
|
||||
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),
|
||||
case acl:match_rule(Host, Access, From) of
|
||||
deny ->
|
||||
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
|
||||
Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN),
|
||||
ejabberd_router:route(To, From, Err);
|
||||
allow ->
|
||||
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),
|
||||
case acl:match_rule(Host, Access, From) of
|
||||
deny ->
|
||||
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
|
||||
Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN),
|
||||
ejabberd_router:route(To, From, Err);
|
||||
allow ->
|
||||
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),
|
||||
case acl:match_rule(Host, Access, From) of
|
||||
deny ->
|
||||
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
|
||||
Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN),
|
||||
ejabberd_router:route(To, From, Err);
|
||||
allow ->
|
||||
announce_motd_delete(Host)
|
||||
@ -237,6 +664,7 @@ send_motd(#jid{luser = LUser, lserver = LServer} = JID) ->
|
||||
ok
|
||||
end.
|
||||
|
||||
%-------------------------------------------------------------------------
|
||||
|
||||
update_tables() ->
|
||||
update_motd_table(),
|
||||
@ -326,3 +754,4 @@ update_motd_users_table() ->
|
||||
?INFO_MSG("Recreating motd_users table", []),
|
||||
mnesia:transform_table(motd_users, ignore, Fields)
|
||||
end.
|
||||
|
||||
|
@ -17,134 +17,210 @@
|
||||
get_local_identity/5,
|
||||
get_local_features/5,
|
||||
get_local_items/5,
|
||||
adhoc_local_items/4,
|
||||
adhoc_local_commands/4,
|
||||
get_sm_identity/5,
|
||||
get_sm_features/5,
|
||||
get_sm_items/5,
|
||||
process_local_iq/3,
|
||||
process_sm_iq/3]).
|
||||
adhoc_sm_items/4,
|
||||
adhoc_sm_commands/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_EJABBERD_CONFIG,
|
||||
?MODULE, process_local_iq, IQDisc),
|
||||
gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_EJABBERD_CONFIG,
|
||||
?MODULE, process_sm_iq, IQDisc),
|
||||
start(Host, _Opts) ->
|
||||
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_identity, Host, ?MODULE, get_local_identity, 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_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.
|
||||
|
||||
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_items, Host, ?MODULE, get_sm_items, 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_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_sm, 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_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) ->
|
||||
Acc;
|
||||
-define(INFO_COMMAND(Name, Lang),
|
||||
?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) ->
|
||||
case {acl:match_rule(LServer, configure, From), Node} of
|
||||
{allow, []} ->
|
||||
case Acc of
|
||||
{result, Features} ->
|
||||
{result, [?NS_EJABBERD_CONFIG | Features]};
|
||||
empty ->
|
||||
{result, [?NS_EJABBERD_CONFIG]}
|
||||
end;
|
||||
case gen_mod:is_loaded(LServer, mod_adhoc) of
|
||||
false ->
|
||||
Acc;
|
||||
_ ->
|
||||
Acc
|
||||
Allow = acl:match_rule(LServer, configure, From),
|
||||
case Node of
|
||||
"config" ->
|
||||
?INFO_RESULT(Allow, [?NS_COMMANDS]);
|
||||
_ ->
|
||||
Acc
|
||||
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) ->
|
||||
Feats = case Acc of
|
||||
{result, Features} -> Features;
|
||||
empty -> []
|
||||
end,
|
||||
case {acl:match_rule(LServer, configure, From), Node} of
|
||||
{deny, _} ->
|
||||
{error, ?ERR_NOT_ALLOWED};
|
||||
{allow, ["config"]} ->
|
||||
?EMPTY_INFO_RESULT;
|
||||
{allow, ["online users"]} ->
|
||||
?EMPTY_INFO_RESULT;
|
||||
{allow, ["all users"]} ->
|
||||
?EMPTY_INFO_RESULT;
|
||||
{allow, ["all users", [$@ | _]]} ->
|
||||
?EMPTY_INFO_RESULT;
|
||||
{allow, ["outgoing s2s" | _]} ->
|
||||
?EMPTY_INFO_RESULT;
|
||||
{allow, ["running nodes"]} ->
|
||||
?EMPTY_INFO_RESULT;
|
||||
{allow, ["stopped nodes"]} ->
|
||||
?EMPTY_INFO_RESULT;
|
||||
{allow, ["running nodes", _ENode]} ->
|
||||
{result, [?NS_STATS | Feats]};
|
||||
{allow, ["running nodes", _ENode, "DB"]} ->
|
||||
{result, [?NS_EJABBERD_CONFIG | Feats]};
|
||||
{allow, ["running nodes", _ENode, "modules"]} ->
|
||||
?EMPTY_INFO_RESULT;
|
||||
{allow, ["running nodes", _ENode, "modules", _]} ->
|
||||
{result, [?NS_EJABBERD_CONFIG | Feats]};
|
||||
{allow, ["running nodes", _ENode, "backup"]} ->
|
||||
?EMPTY_INFO_RESULT;
|
||||
{allow, ["running nodes", _ENode, "backup", _]} ->
|
||||
{result, [?NS_EJABBERD_CONFIG | Feats]};
|
||||
{allow, ["running nodes", _ENode, "import"]} ->
|
||||
?EMPTY_INFO_RESULT;
|
||||
{allow, ["running nodes", _ENode, "import", _]} ->
|
||||
{result, [?NS_EJABBERD_CONFIG | Feats]};
|
||||
{allow, ["config", _]} ->
|
||||
{result, [?NS_EJABBERD_CONFIG | Feats]};
|
||||
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"] ->
|
||||
?INFO_RESULT(Allow, []);
|
||||
["online users"] ->
|
||||
?INFO_RESULT(Allow, []);
|
||||
["all users"] ->
|
||||
?INFO_RESULT(Allow, []);
|
||||
["all users", [$@ | _]] ->
|
||||
?INFO_RESULT(Allow, []);
|
||||
["outgoing s2s" | _] ->
|
||||
?INFO_RESULT(Allow, []);
|
||||
["running nodes"] ->
|
||||
?INFO_RESULT(Allow, []);
|
||||
["stopped nodes"] ->
|
||||
?INFO_RESULT(Allow, []);
|
||||
["running nodes", _ENode] ->
|
||||
?INFO_RESULT(Allow, [?NS_STATS]);
|
||||
["running nodes", _ENode, "DB"] ->
|
||||
?INFO_RESULT(Allow, [?NS_COMMANDS]);
|
||||
["running nodes", _ENode, "modules"] ->
|
||||
?INFO_RESULT(Allow, []);
|
||||
["running nodes", _ENode, "modules", _] ->
|
||||
?INFO_RESULT(Allow, [?NS_COMMANDS]);
|
||||
["running nodes", _ENode, "backup"] ->
|
||||
?INFO_RESULT(Allow, []);
|
||||
["running nodes", _ENode, "backup", _] ->
|
||||
?INFO_RESULT(Allow, [?NS_COMMANDS]);
|
||||
["running nodes", _ENode, "import"] ->
|
||||
?INFO_RESULT(Allow, []);
|
||||
["running nodes", _ENode, "import", _] ->
|
||||
?INFO_RESULT(Allow, [?NS_COMMANDS]);
|
||||
["config", _] ->
|
||||
?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
|
||||
end.
|
||||
|
||||
get_sm_items({error, _Error} = Acc, _From, _To, _Node, _Lang) ->
|
||||
Acc;
|
||||
%%%-----------------------------------------------------------------------
|
||||
|
||||
get_sm_items(Acc, From,
|
||||
#jid{user = User, server = Server, lserver = LServer} = _To,
|
||||
Node, _Lang) ->
|
||||
case {acl:match_rule(LServer, configure, From), Node} of
|
||||
{allow, []} ->
|
||||
Items = case Acc of
|
||||
{result, Its} ->
|
||||
Its;
|
||||
empty ->
|
||||
[]
|
||||
end,
|
||||
{result, Items ++ get_user_resources(User, Server)};
|
||||
#jid{user = User, server = Server, lserver = LServer} = To,
|
||||
Node, Lang) ->
|
||||
case gen_mod:is_loaded(LServer, mod_adhoc) of
|
||||
false ->
|
||||
Acc;
|
||||
_ ->
|
||||
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.
|
||||
|
||||
get_user_resources(User, Server) ->
|
||||
@ -155,31 +231,149 @@ get_user_resources(User, Server) ->
|
||||
{"name", User}], []}
|
||||
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) ->
|
||||
Items = case Acc of
|
||||
{result, Its} ->
|
||||
Its;
|
||||
empty ->
|
||||
adhoc_local_items(Acc, From, #jid{lserver = LServer, server = Server} = To,
|
||||
Lang) ->
|
||||
case acl:match_rule(LServer, configure, From) of
|
||||
allow ->
|
||||
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,
|
||||
case acl:match_rule(LServer, configure, From) of
|
||||
deny when Node /= [] ->
|
||||
{error, ?ERR_NOT_ALLOWED};
|
||||
Nodes = lists:flatten(
|
||||
lists:map(
|
||||
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 ->
|
||||
{result, Items};
|
||||
_ ->
|
||||
case get_local_items(To#jid.lserver, Node,
|
||||
Fallback;
|
||||
allow ->
|
||||
case get_local_items(LServer, LNode,
|
||||
jlib:jid_to_string(To), Lang) of
|
||||
{result, Res} ->
|
||||
{result, Items ++ Res};
|
||||
{result, Res};
|
||||
{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.
|
||||
|
||||
%%%-----------------------------------------------------------------------
|
||||
|
||||
-define(NODE(Name, Node),
|
||||
{xmlelement, "item",
|
||||
[{"jid", Server},
|
||||
@ -422,72 +616,86 @@ get_stopped_nodes(_Lang) ->
|
||||
end, lists:sort(DBNodes))
|
||||
end.
|
||||
|
||||
%-------------------------------------------------------------------------
|
||||
|
||||
|
||||
process_local_iq(From, To, #iq{type = Type, xmlns = XMLNS,
|
||||
lang = Lang, sub_el = SubEl} = IQ) ->
|
||||
case acl:match_rule(To#jid.lserver, configure, From) of
|
||||
-define(COMMANDS_RESULT(Allow, From, To, Request),
|
||||
case Allow of
|
||||
deny ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
|
||||
{error, ?ERR_FORBIDDEN};
|
||||
allow ->
|
||||
case Type of
|
||||
set ->
|
||||
XDataEl = find_xdata_el(SubEl),
|
||||
case XDataEl of
|
||||
false ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ACCEPTABLE]};
|
||||
{xmlelement, _Name, Attrs, _SubEls} ->
|
||||
case xml:get_attr_s("type", Attrs) of
|
||||
"cancel" ->
|
||||
IQ#iq{type = result,
|
||||
sub_el = [{xmlelement, "query",
|
||||
[{"xmlns", XMLNS}], []}]};
|
||||
"submit" ->
|
||||
XData = jlib:parse_xdata_submit(XDataEl),
|
||||
case XData of
|
||||
invalid ->
|
||||
IQ#iq{type = error,
|
||||
sub_el = [SubEl, ?ERR_BAD_REQUEST]};
|
||||
_ ->
|
||||
Node =
|
||||
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
|
||||
adhoc_local_commands(From, To, Request)
|
||||
end).
|
||||
|
||||
adhoc_local_commands(Acc, From, #jid{lserver = LServer} = To,
|
||||
#adhoc_request{node = Node} = Request) ->
|
||||
LNode = string:tokens(Node, "/"),
|
||||
Allow = acl:match_rule(LServer, configure, From),
|
||||
case LNode of
|
||||
["running nodes", _ENode, "DB"] ->
|
||||
?COMMANDS_RESULT(Allow, From, To, Request);
|
||||
["running nodes", _ENode, "modules", _] ->
|
||||
?COMMANDS_RESULT(Allow, From, To, Request);
|
||||
["running nodes", _ENode, "backup", _] ->
|
||||
?COMMANDS_RESULT(Allow, From, To, Request);
|
||||
["running nodes", _ENode, "import", _] ->
|
||||
?COMMANDS_RESULT(Allow, From, To, Request);
|
||||
["config", _] ->
|
||||
?COMMANDS_RESULT(Allow, From, To, Request);
|
||||
_ ->
|
||||
Acc
|
||||
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),
|
||||
{xmlelement, "field", [{"type", Type},
|
||||
{"label", translate:translate(Lang, Label)},
|
||||
@ -1107,83 +1315,60 @@ search_running_node(SNode, [Node | Nodes]) ->
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
process_sm_iq(From, To,
|
||||
#iq{type = Type, xmlns = XMLNS, lang = Lang, sub_el = SubEl} = IQ) ->
|
||||
case acl:match_rule(To#jid.lserver, configure, From) of
|
||||
adhoc_sm_commands(_Acc, From,
|
||||
#jid{user = User, server = Server, lserver = LServer} = _To,
|
||||
#adhoc_request{lang = Lang,
|
||||
node = "config",
|
||||
action = Action,
|
||||
xdata = XData} = Request) ->
|
||||
case acl:match_rule(LServer, configure, From) of
|
||||
deny ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
|
||||
{error, ?ERR_FORBIDDEN};
|
||||
allow ->
|
||||
#jid{user = User, server = Server} = To,
|
||||
case Type of
|
||||
set ->
|
||||
XDataEl = find_xdata_el(SubEl),
|
||||
case XDataEl of
|
||||
false ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ACCEPTABLE]};
|
||||
{xmlelement, _Name, Attrs, _SubEls} ->
|
||||
case xml:get_attr_s("type", Attrs) of
|
||||
"cancel" ->
|
||||
IQ#iq{type = result,
|
||||
sub_el = [{xmlelement, "query",
|
||||
[{"xmlns", XMLNS}], []}]};
|
||||
"submit" ->
|
||||
XData = jlib:parse_xdata_submit(XDataEl),
|
||||
case XData of
|
||||
invalid ->
|
||||
IQ#iq{type = error,
|
||||
sub_el = [SubEl, ?ERR_BAD_REQUEST]};
|
||||
_ ->
|
||||
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
|
||||
}]};
|
||||
%% 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_sm_form(User, Server, "config", Lang) of
|
||||
{result, Form} ->
|
||||
adhoc:produce_response(
|
||||
Request,
|
||||
#adhoc_response{status = executing,
|
||||
elements = Form});
|
||||
{error, Error} ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, Error]}
|
||||
end
|
||||
{error, Error}
|
||||
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;
|
||||
|
||||
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}],
|
||||
[{xmlelement, "title", [],
|
||||
[{xmlcdata,
|
||||
translate:translate(
|
||||
Lang, "Administration of ") ++ User}]},
|
||||
%{xmlelement, "instructions", [],
|
||||
% [{xmlcdata,
|
||||
% translate:translate(
|
||||
% Lang, "Choose host name")}]},
|
||||
{xmlelement, "field",
|
||||
[{"type", "list-single"},
|
||||
{"label", translate:translate(Lang, "Action on user")},
|
||||
@ -1198,49 +1383,36 @@ get_sm_form(User, Server, [], Lang) ->
|
||||
]},
|
||||
?XFIELD("text-private", "Password", "password",
|
||||
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) ->
|
||||
{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
|
||||
{value, {_, ["edit"]}} ->
|
||||
case lists:keysearch("password", 1, XData) of
|
||||
{value, {_, [Password]}} ->
|
||||
ejabberd_auth:set_password(User, Server, Password),
|
||||
{result, []};
|
||||
adhoc:produce_response(Response);
|
||||
_ ->
|
||||
{error, ?ERR_BAD_REQUEST}
|
||||
{error, ?ERR_NOT_ACCEPTABLE}
|
||||
end;
|
||||
{value, {_, ["remove"]}} ->
|
||||
catch ejabberd_auth:remove_user(User, Server),
|
||||
{result, []};
|
||||
adhoc:produce_response(Response);
|
||||
_ ->
|
||||
{error, ?ERR_BAD_REQUEST}
|
||||
{error, ?ERR_NOT_ACCEPTABLE}
|
||||
end;
|
||||
set_sm_form(_User, _Server, _Node, _Lang, _XData) ->
|
||||
|
||||
set_sm_form(_User, _Server, _Node, _Request, _Fields) ->
|
||||
{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 ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
|
||||
get ->
|
||||
SNode = xml:get_tag_attr_s("node", SubEl),
|
||||
Node = string:tokens(SNode, "/"),
|
||||
Node = xml:get_tag_attr_s("node", SubEl),
|
||||
Host = To#jid.lserver,
|
||||
|
||||
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
|
||||
{result, Items} ->
|
||||
ANode = case Node of
|
||||
[] -> [];
|
||||
_ -> [{"node", SNode}]
|
||||
"" -> [];
|
||||
_ -> [{"node", Node}]
|
||||
end,
|
||||
IQ#iq{type = result,
|
||||
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]};
|
||||
get ->
|
||||
Host = To#jid.lserver,
|
||||
SNode = xml:get_tag_attr_s("node", SubEl),
|
||||
Node = string:tokens(SNode, "/"),
|
||||
Node = xml:get_tag_attr_s("node", SubEl),
|
||||
Identity = ejabberd_hooks:run_fold(disco_local_identity,
|
||||
Host,
|
||||
[],
|
||||
@ -156,8 +154,8 @@ process_local_iq_info(From, To, #iq{type = Type, lang = Lang,
|
||||
[From, To, Node, Lang]) of
|
||||
{result, Features} ->
|
||||
ANode = case Node of
|
||||
[] -> [];
|
||||
_ -> [{"node", SNode}]
|
||||
"" -> [];
|
||||
_ -> [{"node", Node}]
|
||||
end,
|
||||
IQ#iq{type = result,
|
||||
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) ->
|
||||
case Type of
|
||||
set ->
|
||||
#jid{user = User, luser = LTo, lserver = ToServer} = To,
|
||||
#jid{luser = LTo, lserver = ToServer} = To,
|
||||
#jid{luser = LFrom, lserver = LServer} = From,
|
||||
Self = (LTo == LFrom) andalso (ToServer == LServer),
|
||||
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;
|
||||
get ->
|
||||
Host = To#jid.lserver,
|
||||
SNode = xml:get_tag_attr_s("node", SubEl),
|
||||
Node = string:tokens(SNode, "/"),
|
||||
Node = xml:get_tag_attr_s("node", SubEl),
|
||||
case ejabberd_hooks:run_fold(disco_sm_items,
|
||||
Host,
|
||||
empty,
|
||||
[From, To, Node, Lang]) of
|
||||
{result, Items} ->
|
||||
ANode = case Node of
|
||||
[] -> [];
|
||||
_ -> [{"node", SNode}]
|
||||
"" -> [];
|
||||
_ -> [{"node", Node}]
|
||||
end,
|
||||
IQ#iq{type = result,
|
||||
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]};
|
||||
get ->
|
||||
Host = To#jid.lserver,
|
||||
SNode = xml:get_tag_attr_s("node", SubEl),
|
||||
Node = string:tokens(SNode, "/"),
|
||||
Node = xml:get_tag_attr_s("node", SubEl),
|
||||
Identity = ejabberd_hooks:run_fold(disco_sm_identity,
|
||||
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
|
||||
{result, Features} ->
|
||||
ANode = case Node of
|
||||
[] -> [];
|
||||
_ -> [{"node", SNode}]
|
||||
"" -> [];
|
||||
_ -> [{"node", Node}]
|
||||
end,
|
||||
IQ#iq{type = result,
|
||||
sub_el = [{xmlelement, "query",
|
||||
@ -384,24 +380,17 @@ get_user_resources(User, Server) ->
|
||||
|
||||
get_publish_items(empty,
|
||||
#jid{luser = LFrom, lserver = LSFrom},
|
||||
#jid{user = User, server = Server, luser = LTo, lserver = LSTo} = _To,
|
||||
#jid{luser = LTo, lserver = LSTo} = _To,
|
||||
Node, _Lang) ->
|
||||
if
|
||||
(LFrom == LTo) and (LSFrom == LSTo) ->
|
||||
% Hack
|
||||
SNode = join(Node, "/"),
|
||||
retrieve_disco_publish({LTo, LSTo}, SNode);
|
||||
retrieve_disco_publish({LTo, LSTo}, Node);
|
||||
true ->
|
||||
empty
|
||||
end;
|
||||
get_publish_items(Acc, _From, _To, _Node, _Lang) ->
|
||||
Acc.
|
||||
|
||||
join(List, Sep) ->
|
||||
lists:foldl(fun(A, "") -> A;
|
||||
(A, Acc) -> Acc ++ Sep ++ A
|
||||
end, "", List).
|
||||
|
||||
process_disco_publish(User, Node, Items) ->
|
||||
F = fun() ->
|
||||
lists:foreach(
|
||||
|
@ -107,7 +107,7 @@ do_route1(Host, ServerHost, Access, From, To, Packet) ->
|
||||
"iq" ->
|
||||
case jlib:iq_query_info(Packet) of
|
||||
#iq{type = get, xmlns = ?NS_DISCO_INFO = XMLNS,
|
||||
sub_el = SubEl} = IQ ->
|
||||
sub_el = _SubEl} = IQ ->
|
||||
Res = IQ#iq{type = result,
|
||||
sub_el = [{xmlelement, "query",
|
||||
[{"xmlns", XMLNS}],
|
||||
@ -123,7 +123,7 @@ do_route1(Host, ServerHost, Access, From, To, Packet) ->
|
||||
#iq{type = get,
|
||||
xmlns = ?NS_REGISTER = XMLNS,
|
||||
lang = Lang,
|
||||
sub_el = SubEl} = IQ ->
|
||||
sub_el = _SubEl} = IQ ->
|
||||
Res = IQ#iq{type = result,
|
||||
sub_el =
|
||||
[{xmlelement, "query",
|
||||
@ -155,7 +155,7 @@ do_route1(Host, ServerHost, Access, From, To, Packet) ->
|
||||
#iq{type = get,
|
||||
xmlns = ?NS_VCARD = XMLNS,
|
||||
lang = Lang,
|
||||
sub_el = SubEl} = IQ ->
|
||||
sub_el = _SubEl} = IQ ->
|
||||
Res = IQ#iq{type = result,
|
||||
sub_el =
|
||||
[{xmlelement, "vCard",
|
||||
@ -380,76 +380,81 @@ iq_get_register_info(Host, From, Lang) ->
|
||||
Lang, "Enter nickname you want to register")}]},
|
||||
?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),
|
||||
LUS = {LUser, LServer},
|
||||
case lists:keysearch("nick", 1, XData) of
|
||||
false ->
|
||||
ErrText = "You must fill in field \"nick\" in the form",
|
||||
{error, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)};
|
||||
{value, {_, [Nick]}} ->
|
||||
F = fun() ->
|
||||
case Nick of
|
||||
"" ->
|
||||
mnesia:delete({muc_registered, {LUS, Host}}),
|
||||
F = fun() ->
|
||||
case Nick of
|
||||
"" ->
|
||||
mnesia:delete({muc_registered, {LUS, Host}}),
|
||||
ok;
|
||||
_ ->
|
||||
Allow =
|
||||
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;
|
||||
_ ->
|
||||
Allow =
|
||||
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
|
||||
true ->
|
||||
false
|
||||
end
|
||||
end,
|
||||
case mnesia:transaction(F) of
|
||||
{atomic, ok} ->
|
||||
{result, []};
|
||||
{atomic, false} ->
|
||||
ErrText = "Specified nickname is already registered",
|
||||
{error, ?ERRT_CONFLICT(Lang, ErrText)};
|
||||
_ ->
|
||||
{error, ?ERR_INTERNAL_SERVER_ERROR}
|
||||
end
|
||||
end
|
||||
end,
|
||||
case mnesia:transaction(F) of
|
||||
{atomic, ok} ->
|
||||
{result, []};
|
||||
{atomic, false} ->
|
||||
ErrText = "Specified nickname is already registered",
|
||||
{error, ?ERRT_CONFLICT(Lang, ErrText)};
|
||||
_ ->
|
||||
{error, ?ERR_INTERNAL_SERVER_ERROR}
|
||||
end.
|
||||
|
||||
process_iq_register_set(Host, From, SubEl, Lang) ->
|
||||
{xmlelement, _Name, _Attrs, Els} = SubEl,
|
||||
case xml:remove_cdata(Els) of
|
||||
[{xmlelement, "x", _Attrs1, _Els1} = XEl] ->
|
||||
case {xml:get_tag_attr_s("xmlns", XEl),
|
||||
xml:get_tag_attr_s("type", XEl)} of
|
||||
{?NS_XDATA, "cancel"} ->
|
||||
{result, []};
|
||||
{?NS_XDATA, "submit"} ->
|
||||
XData = jlib:parse_xdata_submit(XEl),
|
||||
case XData of
|
||||
invalid ->
|
||||
{error, ?ERR_BAD_REQUEST};
|
||||
case xml:get_subtag(SubEl, "remove") of
|
||||
false ->
|
||||
case xml:remove_cdata(Els) of
|
||||
[{xmlelement, "x", _Attrs1, _Els1} = XEl] ->
|
||||
case {xml:get_tag_attr_s("xmlns", XEl),
|
||||
xml:get_tag_attr_s("type", XEl)} of
|
||||
{?NS_XDATA, "cancel"} ->
|
||||
{result, []};
|
||||
{?NS_XDATA, "submit"} ->
|
||||
XData = jlib:parse_xdata_submit(XEl),
|
||||
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;
|
||||
_ ->
|
||||
{error, ?ERR_BAD_REQUEST}
|
||||
end;
|
||||
_ ->
|
||||
{error, ?ERR_BAD_REQUEST}
|
||||
iq_set_register_info(Host, From, "", Lang)
|
||||
end.
|
||||
|
||||
iq_get_vcard(Lang) ->
|
||||
|
@ -101,7 +101,7 @@ start(Host, ServerHost, Access, Room, Opts) ->
|
||||
%% ignore |
|
||||
%% {stop, StopReason}
|
||||
%%----------------------------------------------------------------------
|
||||
init([Host, ServerHost, Access, Room, Creator, Nick]) ->
|
||||
init([Host, ServerHost, Access, Room, Creator, _Nick]) ->
|
||||
State = set_affiliation(Creator, owner,
|
||||
#state{host = Host,
|
||||
server_host = ServerHost,
|
||||
@ -559,16 +559,11 @@ normal_state({route, From, ToNick,
|
||||
end,
|
||||
{next_state, normal_state, StateData};
|
||||
|
||||
normal_state(Event, StateData) ->
|
||||
normal_state(_Event, StateData) ->
|
||||
{next_state, normal_state, StateData}.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: handle_event/3
|
||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
||||
@ -862,15 +857,13 @@ filter_presence({xmlelement, "presence", Attrs, Els}) ->
|
||||
case El of
|
||||
{xmlcdata, _} ->
|
||||
false;
|
||||
{xmlelement, Name1, Attrs1, _Els1} ->
|
||||
{xmlelement, _Name1, Attrs1, _Els1} ->
|
||||
XMLNS = xml:get_attr_s("xmlns", Attrs1),
|
||||
case {Name1, XMLNS} of
|
||||
{"show", ""} ->
|
||||
true;
|
||||
{"status", ""} ->
|
||||
true;
|
||||
case XMLNS of
|
||||
?NS_MUC ++ _ ->
|
||||
false;
|
||||
_ ->
|
||||
false
|
||||
true
|
||||
end
|
||||
end
|
||||
end, Els),
|
||||
@ -971,6 +964,20 @@ add_new_user(From, Nick, {xmlelement, _, Attrs, Els} = Packet, StateData) ->
|
||||
add_user_presence(
|
||||
From, Packet,
|
||||
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_existing_presences(From, NewState),
|
||||
Shift = count_stanza_shift(Nick, Els, NewState),
|
||||
@ -1550,23 +1557,23 @@ process_admin_items_set(UJID, Items, Lang, StateData) ->
|
||||
set_affiliation_and_reason(
|
||||
JID, outcast, Reason,
|
||||
set_role(JID, none, SD));
|
||||
{JID, affiliation, A, Reason} when
|
||||
{JID, affiliation, A, _Reason} when
|
||||
(A == admin) or (A == owner) ->
|
||||
SD1 = set_affiliation(JID, A, SD),
|
||||
SD2 = set_role(JID, moderator, SD1),
|
||||
send_update_presence(JID, SD2),
|
||||
SD2;
|
||||
{JID, affiliation, member, Reason} ->
|
||||
{JID, affiliation, member, _Reason} ->
|
||||
SD1 = set_affiliation(
|
||||
JID, member, SD),
|
||||
SD2 = set_role(JID, participant, SD1),
|
||||
send_update_presence(JID, SD2),
|
||||
SD2;
|
||||
{JID, role, R, Reason} ->
|
||||
{JID, role, R, _Reason} ->
|
||||
SD1 = set_role(JID, R, SD),
|
||||
catch send_new_presence(JID, SD1),
|
||||
SD1;
|
||||
{JID, affiliation, A, Reason} ->
|
||||
{JID, affiliation, A, _Reason} ->
|
||||
SD1 = set_affiliation(JID, A, SD),
|
||||
send_update_presence(JID, SD1),
|
||||
SD1
|
||||
@ -1593,7 +1600,7 @@ process_admin_items_set(UJID, Items, Lang, StateData) ->
|
||||
end.
|
||||
|
||||
|
||||
find_changed_items(UJID, UAffiliation, URole, [], _Lang, StateData, Res) ->
|
||||
find_changed_items(_UJID, _UAffiliation, _URole, [], _Lang, _StateData, Res) ->
|
||||
{result, Res};
|
||||
find_changed_items(UJID, UAffiliation, URole, [{xmlcdata, _} | Items],
|
||||
Lang, StateData, Res) ->
|
||||
@ -1721,143 +1728,143 @@ find_changed_items(_UJID, _UAffiliation, _URole, _Items,
|
||||
{error, ?ERR_BAD_REQUEST}.
|
||||
|
||||
|
||||
can_change_ra(FAffiliation, FRole,
|
||||
TAffiliation, TRole,
|
||||
can_change_ra(_FAffiliation, _FRole,
|
||||
TAffiliation, _TRole,
|
||||
affiliation, Value)
|
||||
when (TAffiliation == Value) ->
|
||||
nothing;
|
||||
can_change_ra(FAffiliation, FRole,
|
||||
TAffiliation, TRole,
|
||||
can_change_ra(_FAffiliation, _FRole,
|
||||
_TAffiliation, TRole,
|
||||
role, Value)
|
||||
when (TRole == Value) ->
|
||||
nothing;
|
||||
can_change_ra(FAffiliation, FRole,
|
||||
outcast, TRole,
|
||||
can_change_ra(FAffiliation, _FRole,
|
||||
outcast, _TRole,
|
||||
affiliation, none)
|
||||
when (FAffiliation == owner) or (FAffiliation == admin) ->
|
||||
true;
|
||||
can_change_ra(FAffiliation, FRole,
|
||||
outcast, TRole,
|
||||
can_change_ra(FAffiliation, _FRole,
|
||||
outcast, _TRole,
|
||||
affiliation, member)
|
||||
when (FAffiliation == owner) or (FAffiliation == admin) ->
|
||||
true;
|
||||
can_change_ra(owner, FRole,
|
||||
outcast, TRole,
|
||||
can_change_ra(owner, _FRole,
|
||||
outcast, _TRole,
|
||||
affiliation, admin) ->
|
||||
true;
|
||||
can_change_ra(owner, FRole,
|
||||
outcast, TRole,
|
||||
can_change_ra(owner, _FRole,
|
||||
outcast, _TRole,
|
||||
affiliation, owner) ->
|
||||
true;
|
||||
can_change_ra(FAffiliation, FRole,
|
||||
none, TRole,
|
||||
can_change_ra(FAffiliation, _FRole,
|
||||
none, _TRole,
|
||||
affiliation, outcast)
|
||||
when (FAffiliation == owner) or (FAffiliation == admin) ->
|
||||
true;
|
||||
can_change_ra(FAffiliation, FRole,
|
||||
none, TRole,
|
||||
can_change_ra(FAffiliation, _FRole,
|
||||
none, _TRole,
|
||||
affiliation, member)
|
||||
when (FAffiliation == owner) or (FAffiliation == admin) ->
|
||||
true;
|
||||
can_change_ra(owner, FRole,
|
||||
none, TRole,
|
||||
can_change_ra(owner, _FRole,
|
||||
none, _TRole,
|
||||
affiliation, admin) ->
|
||||
true;
|
||||
can_change_ra(owner, FRole,
|
||||
none, TRole,
|
||||
can_change_ra(owner, _FRole,
|
||||
none, _TRole,
|
||||
affiliation, owner) ->
|
||||
true;
|
||||
can_change_ra(FAffiliation, FRole,
|
||||
member, TRole,
|
||||
can_change_ra(FAffiliation, _FRole,
|
||||
member, _TRole,
|
||||
affiliation, outcast)
|
||||
when (FAffiliation == owner) or (FAffiliation == admin) ->
|
||||
true;
|
||||
can_change_ra(FAffiliation, FRole,
|
||||
member, TRole,
|
||||
can_change_ra(FAffiliation, _FRole,
|
||||
member, _TRole,
|
||||
affiliation, none)
|
||||
when (FAffiliation == owner) or (FAffiliation == admin) ->
|
||||
true;
|
||||
can_change_ra(owner, FRole,
|
||||
member, TRole,
|
||||
can_change_ra(owner, _FRole,
|
||||
member, _TRole,
|
||||
affiliation, admin) ->
|
||||
true;
|
||||
can_change_ra(owner, FRole,
|
||||
member, TRole,
|
||||
can_change_ra(owner, _FRole,
|
||||
member, _TRole,
|
||||
affiliation, owner) ->
|
||||
true;
|
||||
can_change_ra(owner, FRole,
|
||||
admin, TRole,
|
||||
can_change_ra(owner, _FRole,
|
||||
admin, _TRole,
|
||||
affiliation, _Affiliation) ->
|
||||
true;
|
||||
can_change_ra(owner, FRole,
|
||||
owner, TRole,
|
||||
can_change_ra(owner, _FRole,
|
||||
owner, _TRole,
|
||||
affiliation, _Affiliation) ->
|
||||
true;
|
||||
can_change_ra(FAffiliation, FRole,
|
||||
TAffiliation, TRole,
|
||||
affiliation, Value) ->
|
||||
can_change_ra(_FAffiliation, _FRole,
|
||||
_TAffiliation, _TRole,
|
||||
affiliation, _Value) ->
|
||||
false;
|
||||
can_change_ra(FAffiliation, moderator,
|
||||
TAffiliation, visitor,
|
||||
can_change_ra(_FAffiliation, moderator,
|
||||
_TAffiliation, visitor,
|
||||
role, none) ->
|
||||
true;
|
||||
can_change_ra(FAffiliation, moderator,
|
||||
TAffiliation, visitor,
|
||||
can_change_ra(_FAffiliation, moderator,
|
||||
_TAffiliation, visitor,
|
||||
role, participant) ->
|
||||
true;
|
||||
can_change_ra(FAffiliation, FRole,
|
||||
TAffiliation, visitor,
|
||||
can_change_ra(FAffiliation, _FRole,
|
||||
_TAffiliation, visitor,
|
||||
role, moderator)
|
||||
when (FAffiliation == owner) or (FAffiliation == admin) ->
|
||||
true;
|
||||
can_change_ra(FAffiliation, moderator,
|
||||
TAffiliation, participant,
|
||||
can_change_ra(_FAffiliation, moderator,
|
||||
_TAffiliation, participant,
|
||||
role, none) ->
|
||||
true;
|
||||
can_change_ra(FAffiliation, moderator,
|
||||
TAffiliation, participant,
|
||||
can_change_ra(_FAffiliation, moderator,
|
||||
_TAffiliation, participant,
|
||||
role, visitor) ->
|
||||
true;
|
||||
can_change_ra(FAffiliation, FRole,
|
||||
TAffiliation, participant,
|
||||
can_change_ra(FAffiliation, _FRole,
|
||||
_TAffiliation, participant,
|
||||
role, moderator)
|
||||
when (FAffiliation == owner) or (FAffiliation == admin) ->
|
||||
true;
|
||||
can_change_ra(FAffiliation, FRole,
|
||||
can_change_ra(_FAffiliation, _FRole,
|
||||
owner, moderator,
|
||||
role, visitor) ->
|
||||
false;
|
||||
can_change_ra(owner, FRole,
|
||||
TAffiliation, moderator,
|
||||
can_change_ra(owner, _FRole,
|
||||
_TAffiliation, moderator,
|
||||
role, visitor) ->
|
||||
true;
|
||||
can_change_ra(FAffiliation, FRole,
|
||||
can_change_ra(_FAffiliation, _FRole,
|
||||
admin, moderator,
|
||||
role, visitor) ->
|
||||
false;
|
||||
can_change_ra(admin, FRole,
|
||||
TAffiliation, moderator,
|
||||
can_change_ra(admin, _FRole,
|
||||
_TAffiliation, moderator,
|
||||
role, visitor) ->
|
||||
true;
|
||||
can_change_ra(FAffiliation, FRole,
|
||||
can_change_ra(_FAffiliation, _FRole,
|
||||
owner, moderator,
|
||||
role, participant) ->
|
||||
false;
|
||||
can_change_ra(owner, FRole,
|
||||
TAffiliation, moderator,
|
||||
can_change_ra(owner, _FRole,
|
||||
_TAffiliation, moderator,
|
||||
role, participant) ->
|
||||
true;
|
||||
can_change_ra(FAffiliation, FRole,
|
||||
can_change_ra(_FAffiliation, _FRole,
|
||||
admin, moderator,
|
||||
role, participant) ->
|
||||
false;
|
||||
can_change_ra(admin, FRole,
|
||||
TAffiliation, moderator,
|
||||
can_change_ra(admin, _FRole,
|
||||
_TAffiliation, moderator,
|
||||
role, participant) ->
|
||||
true;
|
||||
can_change_ra(FAffiliation, FRole,
|
||||
TAffiliation, TRole,
|
||||
role, Value) ->
|
||||
can_change_ra(_FAffiliation, _FRole,
|
||||
_TAffiliation, _TRole,
|
||||
role, _Value) ->
|
||||
false.
|
||||
|
||||
|
||||
@ -1887,13 +1894,13 @@ send_kickban_presence(JID, Reason, Code, StateData) ->
|
||||
end, LJIDs).
|
||||
|
||||
send_kickban_presence1(UJID, Reason, Code, StateData) ->
|
||||
{ok, #user{jid = RealJID,
|
||||
{ok, #user{jid = _RealJID,
|
||||
nick = Nick}} =
|
||||
?DICT:find(jlib:jid_tolower(UJID), StateData#state.users),
|
||||
Affiliation = get_affiliation(UJID, StateData),
|
||||
SAffiliation = affiliation_to_list(Affiliation),
|
||||
lists:foreach(
|
||||
fun({LJID, Info}) ->
|
||||
fun({_LJID, Info}) ->
|
||||
ItemAttrs = [{"affiliation", SAffiliation},
|
||||
{"role", "none"}],
|
||||
ItemEls = case Reason of
|
||||
@ -1922,9 +1929,9 @@ process_iq_owner(From, set, Lang, SubEl, StateData) ->
|
||||
FAffiliation = get_affiliation(From, StateData),
|
||||
case FAffiliation of
|
||||
owner ->
|
||||
{xmlelement, Name, Attrs, Els} = SubEl,
|
||||
{xmlelement, _Name, _Attrs, Els} = SubEl,
|
||||
case xml:remove_cdata(Els) of
|
||||
[{xmlelement, "x", Attrs1, Els1} = XEl] ->
|
||||
[{xmlelement, "x", _Attrs1, _Els1} = XEl] ->
|
||||
case {xml:get_tag_attr_s("xmlns", XEl),
|
||||
xml:get_tag_attr_s("type", XEl)} of
|
||||
{?NS_XDATA, "cancel"} ->
|
||||
@ -1934,8 +1941,8 @@ process_iq_owner(From, set, Lang, SubEl, StateData) ->
|
||||
_ ->
|
||||
{error, ?ERR_BAD_REQUEST}
|
||||
end;
|
||||
[{xmlelement, "destroy", Attrs1, Els1}] ->
|
||||
destroy_room(Els1, StateData);
|
||||
[{xmlelement, "destroy", _Attrs1, _Els1} = SubEl1] ->
|
||||
destroy_room(SubEl1, StateData);
|
||||
Items ->
|
||||
process_admin_items_set(From, Items, Lang, StateData)
|
||||
end;
|
||||
@ -1948,7 +1955,7 @@ process_iq_owner(From, get, Lang, SubEl, StateData) ->
|
||||
FAffiliation = get_affiliation(From, StateData),
|
||||
case FAffiliation of
|
||||
owner ->
|
||||
{xmlelement, Name, Attrs, Els} = SubEl,
|
||||
{xmlelement, _Name, _Attrs, Els} = SubEl,
|
||||
case xml:remove_cdata(Els) of
|
||||
[] ->
|
||||
get_config(Lang, StateData);
|
||||
@ -2009,39 +2016,18 @@ get_config(Lang, StateData) ->
|
||||
[{xmlcdata, translate:translate(Lang, "Configuration for ") ++
|
||||
jlib:jid_to_string(StateData#state.jid)}]},
|
||||
?STRINGXFIELD("Room title",
|
||||
"title",
|
||||
Config#config.title),
|
||||
?BOOLXFIELD("Allow users to change subject?",
|
||||
"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?",
|
||||
"title",
|
||||
Config#config.title),
|
||||
?BOOLXFIELD("Make room persistent",
|
||||
"persistent",
|
||||
Config#config.persistent),
|
||||
?BOOLXFIELD("Make room moderated?",
|
||||
"moderated",
|
||||
Config#config.moderated),
|
||||
?BOOLXFIELD("Default users as members?",
|
||||
"members_by_default",
|
||||
Config#config.members_by_default),
|
||||
?BOOLXFIELD("Make room members only?",
|
||||
"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?",
|
||||
?BOOLXFIELD("Make room public searchable",
|
||||
"public",
|
||||
Config#config.public),
|
||||
?BOOLXFIELD("Make participants list public",
|
||||
"public_list",
|
||||
Config#config.public_list),
|
||||
?BOOLXFIELD("Make room password protected",
|
||||
"password_protected",
|
||||
Config#config.password_protected),
|
||||
?PRIVATEXFIELD("Password",
|
||||
@ -2050,10 +2036,31 @@ get_config(Lang, StateData) ->
|
||||
true -> Config#config.password;
|
||||
false -> ""
|
||||
end),
|
||||
?BOOLXFIELD("Make room anonymous?",
|
||||
?BOOLXFIELD("Make room semianonymous",
|
||||
"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",
|
||||
Config#config.logging)
|
||||
],
|
||||
@ -2125,7 +2132,7 @@ set_xoption([{"anonymous", [Val]} | Opts], Config) ->
|
||||
?SET_BOOL_XOPT(anonymous, Val);
|
||||
set_xoption([{"logging", [Val]} | Opts], Config) ->
|
||||
?SET_BOOL_XOPT(logging, Val);
|
||||
set_xoption([_ | Opts], Config) ->
|
||||
set_xoption([_ | _Opts], _Config) ->
|
||||
{error, ?ERR_BAD_REQUEST}.
|
||||
|
||||
|
||||
@ -2203,17 +2210,15 @@ make_opts(StateData) ->
|
||||
|
||||
|
||||
|
||||
destroy_room(DEls, StateData) ->
|
||||
destroy_room(DEl, StateData) ->
|
||||
lists:foreach(
|
||||
fun({LJID, Info}) ->
|
||||
fun({_LJID, Info}) ->
|
||||
Nick = Info#user.nick,
|
||||
ItemAttrs = [{"affiliation", "none"},
|
||||
{"role", "none"}],
|
||||
Packet = {xmlelement, "presence", [{"type", "unavailable"}],
|
||||
[{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}],
|
||||
[{xmlelement, "item", ItemAttrs, []},
|
||||
{xmlelement, "destroy", [],
|
||||
DEls}]}]},
|
||||
[{xmlelement, "item", ItemAttrs, []}, DEl]}]},
|
||||
ejabberd_router:route(
|
||||
jlib:jid_replace_resource(StateData#state.jid, Nick),
|
||||
Info#user.jid,
|
||||
@ -2243,10 +2248,10 @@ destroy_room(DEls, StateData) ->
|
||||
?FEATURE(Fiffalse)
|
||||
end).
|
||||
|
||||
process_iq_disco_info(From, set, Lang, StateData) ->
|
||||
process_iq_disco_info(_From, set, _Lang, _StateData) ->
|
||||
{error, ?ERR_NOT_ALLOWED};
|
||||
|
||||
process_iq_disco_info(From, get, Lang, StateData) ->
|
||||
process_iq_disco_info(_From, get, Lang, StateData) ->
|
||||
Config = StateData#state.config,
|
||||
{result, [{xmlelement, "identity",
|
||||
[{"category", "conference"},
|
||||
@ -2266,13 +2271,33 @@ process_iq_disco_info(From, get, Lang, StateData) ->
|
||||
"muc_moderated", "muc_unmoderated"),
|
||||
?CONFIG_OPT_TO_FEATURE(Config#config.password_protected,
|
||||
"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};
|
||||
|
||||
process_iq_disco_items(From, get, Lang, StateData) ->
|
||||
process_iq_disco_items(From, get, _Lang, StateData) ->
|
||||
FAffiliation = get_affiliation(From, StateData),
|
||||
FRole = get_role(From, StateData),
|
||||
case ((StateData#state.config)#config.public_list == true) orelse
|
||||
@ -2282,7 +2307,7 @@ process_iq_disco_items(From, get, Lang, StateData) ->
|
||||
true ->
|
||||
UList =
|
||||
lists:map(
|
||||
fun({LJID, Info}) ->
|
||||
fun({_LJID, Info}) ->
|
||||
Nick = Info#user.nick,
|
||||
{xmlelement, "item",
|
||||
[{"jid", jlib:jid_to_string(
|
||||
@ -2314,11 +2339,11 @@ check_invitation(From, Els, StateData) ->
|
||||
CanInvite = (StateData#state.config)#config.allow_user_invites
|
||||
orelse (FAffiliation == admin) orelse (FAffiliation == owner),
|
||||
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
|
||||
?NS_MUC_USER ->
|
||||
case xml:remove_cdata(Els1) of
|
||||
[{xmlelement, "invite", Attrs2, Els2} = InviteEl] ->
|
||||
[{xmlelement, "invite", Attrs2, _Els2} = InviteEl] ->
|
||||
case jlib:string_to_jid(
|
||||
xml:get_attr_s("to", Attrs2)) of
|
||||
error ->
|
||||
|
Loading…
Reference in New Issue
Block a user