25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-10-31 15:21:38 +01:00

Merge branch '2.1.x' into 2.2.x

This commit is contained in:
Christophe Romain 2010-08-05 10:20:47 +02:00
commit 7be707f7bc
18 changed files with 656 additions and 412 deletions

View File

@ -2,7 +2,7 @@
"http://www.w3.org/TR/REC-html40/loose.dtd"> "http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML> <HTML>
<HEAD> <HEAD>
<TITLE>Ejabberd 2.1.x Developers Guide <TITLE>Ejabberd 2.1.5 Developers Guide
</TITLE> </TITLE>
<META http-equiv="Content-Type" content="text/html; charset=US-ASCII"> <META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
@ -49,7 +49,7 @@ TD P{margin:0px;}
<!--HEVEA command line is: /usr/bin/hevea -fix -pedantic dev.tex --> <!--HEVEA command line is: /usr/bin/hevea -fix -pedantic dev.tex -->
<!--CUT DEF section 1 --><P><A NAME="titlepage"></A> <!--CUT DEF section 1 --><P><A NAME="titlepage"></A>
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.x Developers Guide</H1><H3 CLASS="titlerest">Alexey Shchepin<BR> </P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.5 Developers Guide</H1><H3 CLASS="titlerest">Alexey Shchepin<BR>
<A HREF="mailto:alexey@sevcom.net"><TT>mailto:alexey@sevcom.net</TT></A><BR> <A HREF="mailto:alexey@sevcom.net"><TT>mailto:alexey@sevcom.net</TT></A><BR>
<A HREF="xmpp:aleksey@jabber.ru"><TT>xmpp:aleksey@jabber.ru</TT></A></H3></TD></TR> <A HREF="xmpp:aleksey@jabber.ru"><TT>xmpp:aleksey@jabber.ru</TT></A></H3></TD></TR>
</TABLE><DIV CLASS="center"> </TABLE><DIV CLASS="center">

View File

@ -2,7 +2,7 @@
"http://www.w3.org/TR/REC-html40/loose.dtd"> "http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML> <HTML>
<HEAD> <HEAD>
<TITLE>Ejabberd 2.1.x Feature Sheet <TITLE>Ejabberd 2.1.5 Feature Sheet
</TITLE> </TITLE>
<META http-equiv="Content-Type" content="text/html; charset=US-ASCII"> <META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
@ -50,7 +50,7 @@ SPAN{width:20%; float:right; text-align:left; margin-left:auto;}
<!--HEVEA command line is: /usr/bin/hevea -fix -pedantic features.tex --> <!--HEVEA command line is: /usr/bin/hevea -fix -pedantic features.tex -->
<!--CUT DEF section 1 --><P><A NAME="titlepage"></A> <!--CUT DEF section 1 --><P><A NAME="titlepage"></A>
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.x Feature Sheet</H1><H3 CLASS="titlerest">Sander Devrieze<BR> </P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.5 Feature Sheet</H1><H3 CLASS="titlerest">Sander Devrieze<BR>
<A HREF="mailto:s.devrieze@pandora.be"><TT>mailto:s.devrieze@pandora.be</TT></A><BR> <A HREF="mailto:s.devrieze@pandora.be"><TT>mailto:s.devrieze@pandora.be</TT></A><BR>
<A HREF="xmpp:sander@devrieze.dyndns.org"><TT>xmpp:sander@devrieze.dyndns.org</TT></A></H3></TD></TR> <A HREF="xmpp:sander@devrieze.dyndns.org"><TT>xmpp:sander@devrieze.dyndns.org</TT></A></H3></TD></TR>
</TABLE><DIV CLASS="center"> </TABLE><DIV CLASS="center">

View File

@ -6,7 +6,7 @@
ejabberd 2.1.x ejabberd 2.1.5
Installation and Operation Guide Installation and Operation Guide
@ -76,7 +76,7 @@ BLOCKQUOTE.figure DIV.center DIV.center HR{display:none;}
<HR SIZE=2><BR> <HR SIZE=2><BR>
<BR> <BR>
<TABLE CELLSPACING=6 CELLPADDING=0><TR><TD ALIGN=right NOWRAP> <FONT SIZE=6><B>ejabberd 2.1.x </B></FONT></TD></TR> <TABLE CELLSPACING=6 CELLPADDING=0><TR><TD ALIGN=right NOWRAP> <FONT SIZE=6><B>ejabberd 2.1.5 </B></FONT></TD></TR>
<TR><TD ALIGN=right NOWRAP>&nbsp;</TD></TR> <TR><TD ALIGN=right NOWRAP>&nbsp;</TD></TR>
<TR><TD ALIGN=right NOWRAP> <FONT SIZE=6>Installation and Operation Guide</FONT></TD></TR> <TR><TD ALIGN=right NOWRAP> <FONT SIZE=6>Installation and Operation Guide</FONT></TD></TR>
</TABLE><BR> </TABLE><BR>
@ -1060,7 +1060,9 @@ There are also <A HREF="http://www.ejabberd.im/extauth">several example authenti
</P><DL CLASS="description"><DT CLASS="dt-description"> </P><DL CLASS="description"><DT CLASS="dt-description">
<B><TT>{extauth_program, PathToScript}</TT></B></DT><DD CLASS="dd-description"> <B><TT>{extauth_program, PathToScript}</TT></B></DT><DD CLASS="dd-description">
Indicate in this option the full path to the external authentication script. Indicate in this option the full path to the external authentication script.
The script must be executable by ejabberd.</DD><DT CLASS="dt-description"><B><TT>{extauth_cache, false|CacheTimeInteger}</TT></B></DT><DD CLASS="dd-description"> The script must be executable by ejabberd.</DD><DT CLASS="dt-description"><B><TT>{extauth_instances, Integer}</TT></B></DT><DD CLASS="dd-description">
Indicate how many instances of the script to run simultaneously to serve authentication in the virtual host.
The default value is the minimum number: 1.</DD><DT CLASS="dt-description"><B><TT>{extauth_cache, false|CacheTimeInteger}</TT></B></DT><DD CLASS="dd-description">
The value <TT>false</TT> disables the caching feature, this is the default. The value <TT>false</TT> disables the caching feature, this is the default.
The integer <TT>0</TT> (zero) enables caching for statistics, but doesn&#X2019;t use that cached information to authenticate users. The integer <TT>0</TT> (zero) enables caching for statistics, but doesn&#X2019;t use that cached information to authenticate users.
If another integer value is set, caching is enabled both for statistics and for authentication: If another integer value is set, caching is enabled both for statistics and for authentication:
@ -1069,10 +1071,12 @@ the authentication information since the user last disconnected,
to verify again the user authentication without querying again the extauth script. to verify again the user authentication without querying again the extauth script.
Note: caching should not be enabled in a host if internal auth is also enabled. Note: caching should not be enabled in a host if internal auth is also enabled.
If caching is enabled, <TT>mod_last</TT> or <TT>mod_last_odbc</TT> must be enabled also in that vhost. If caching is enabled, <TT>mod_last</TT> or <TT>mod_last_odbc</TT> must be enabled also in that vhost.
</DD></DL><P>This example sets external authentication, the extauth script, and enables caching for 10 minutes: </DD></DL><P>This example sets external authentication, the extauth script, enables caching for 10 minutes,
and starts three instances of the script for each virtual host defined in ejabberd:
</P><PRE CLASS="verbatim">{auth_method, [external]}. </P><PRE CLASS="verbatim">{auth_method, [external]}.
{extauth_program, "/etc/ejabberd/JabberAuth.class.php"}. {extauth_program, "/etc/ejabberd/JabberAuth.class.php"}.
{extauth_cache, 600}. {extauth_cache, 600}.
{extauth_instances, 3}.
</PRE><P> <A NAME="saslanonymous"></A> </P><!--TOC subsubsection SASL Anonymous and Anonymous Login--> </PRE><P> <A NAME="saslanonymous"></A> </P><!--TOC subsubsection SASL Anonymous and Anonymous Login-->
<H4 CLASS="subsubsection"><!--SEC ANCHOR --><A HREF="#saslanonymous">SASL Anonymous and Anonymous Login</A></H4><!--SEC END --><P> <A NAME="saslanonymous"></A> <H4 CLASS="subsubsection"><!--SEC ANCHOR --><A HREF="#saslanonymous">SASL Anonymous and Anonymous Login</A></H4><!--SEC END --><P> <A NAME="saslanonymous"></A>
</P><P>The value <TT>anonymous</TT> will enable the internal authentication method.</P><P>The anonymous authentication method can be configured with the following </P><P>The value <TT>anonymous</TT> will enable the internal authentication method.</P><P>The anonymous authentication method can be configured with the following

View File

@ -1239,6 +1239,10 @@ These are the specific options:
Indicate in this option the full path to the external authentication script. Indicate in this option the full path to the external authentication script.
The script must be executable by ejabberd. The script must be executable by ejabberd.
\titem{\{extauth\_instances, Integer\}}
Indicate how many instances of the script to run simultaneously to serve authentication in the virtual host.
The default value is the minimum number: 1.
\titem{\{extauth\_cache, false|CacheTimeInteger\}} \titem{\{extauth\_cache, false|CacheTimeInteger\}}
The value \term{false} disables the caching feature, this is the default. The value \term{false} disables the caching feature, this is the default.
The integer \term{0} (zero) enables caching for statistics, but doesn't use that cached information to authenticate users. The integer \term{0} (zero) enables caching for statistics, but doesn't use that cached information to authenticate users.
@ -1250,11 +1254,13 @@ These are the specific options:
If caching is enabled, \term{mod\_last} or \term{mod\_last\_odbc} must be enabled also in that vhost. If caching is enabled, \term{mod\_last} or \term{mod\_last\_odbc} must be enabled also in that vhost.
\end{description} \end{description}
This example sets external authentication, the extauth script, and enables caching for 10 minutes: This example sets external authentication, the extauth script, enables caching for 10 minutes,
and starts three instances of the script for each virtual host defined in ejabberd:
\begin{verbatim} \begin{verbatim}
{auth_method, [external]}. {auth_method, [external]}.
{extauth_program, "/etc/ejabberd/JabberAuth.class.php"}. {extauth_program, "/etc/ejabberd/JabberAuth.class.php"}.
{extauth_cache, 600}. {extauth_cache, 600}.
{extauth_instances, 3}.
\end{verbatim} \end{verbatim}
\makesubsubsection{saslanonymous}{SASL Anonymous and Anonymous Login} \makesubsubsection{saslanonymous}{SASL Anonymous and Anonymous Login}

View File

@ -0,0 +1,70 @@
Release Notes
ejabberd 2.1.5
ejabberd 2.1.5 is the fifth release in ejabberd 2.1.x branch,
and includes several minor bugfixes and a few improvements.
Read more details about the changes in:
http://redir.process-one.net/ejabberd-2.1.4
Download the source code and installers from:
http://www.process-one.net/en/ejabberd/
This is the full list of changes:
* Authentication
- Extauth: Support parallel script running (EJAB-1280)
- mod_register: Return Registered element when account exists
* ejabberdctl
- Fix print of command result that contains ~
- Fix problem when FIREWALL_WINDOW options for erl kernel were used
- Fix typo in update_list command (EJAB-1237)
- Some systems delete the lock dir; in such case don't use flock at all
- The command Update now returns meaningful message and exit-status (EJAB-1237)
* HTTP-Bind (BOSH)
- Don't say v1.2 in the Bind HTTP page
- New optional BOSH connection attribute process-delay (EJAB-1257)
* MUC
- Document the mod_muc option captcha_protected
- Now admins are able to see private rooms in disco (EJAB-1269)
- Show some more room options in the log file
* ODBC
- Correct handling of SQL boolean types (EJAB-1275)
- Discard too old queued requests (the caller has already got a timeout)
- Fixes wrong SQL escaping when --enable-full-xml is set
- Use ets insead of asking supervisor in ejabberd_odbc_sup:get_pids/1
* Pubsub, PEP and Caps
- Enforce disco features results (EJAB-1033, EJAB-1228, EJAB-1238)
- Support all the hash functions required by Caps XEP-0115
* Requirements
- Fixed support for Erlang R12; which doesn't support: true andalso ok
- Support OTP R14A by using public_key library instead of old ssl (EJAB-953)
- Requirement of OpenSSL increased from 0.9.6 to 0.9.8
- OpenSSL is now required, not optional
* Other
- Don't ask for client certificate when using tls (EJAB-1267)
- Fix typo in --enable-transient_supervisors
- Fix privacy check when serving local Last (EJAB-1271)
- Inform client that SSL session caching is disabled
- New configure option: --enable-nif
- Use driver allocator in C files for reflecting memory in erlang:memory(system)
- Debug: New p1_prof compiled with: make debugtools=true
- Debug: Added functions to collect stats about queues, memory, reductions etc
- HTTP: Log error if request has ambiguous Host header (EJAB-1261)
- Logs: When logging s2s out connection attempt or success, log if TLS is used
- Shared Rosters: When account is deleted, delete also member of stored rosters
Bug reports
You can officially report bugs on ProcessOne support site:
http://support.process-one.net/

View File

@ -1,2 +1,2 @@
% ejabberd version (automatically generated). % ejabberd version (automatically generated).
\newcommand{\version}{2.1.x} \newcommand{\version}{2.1.5}

18
src/configure vendored
View File

@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.65 for ejabberd 2.1.x. # Generated by GNU Autoconf 2.65 for ejabberd 2.1.5.
# #
# Report bugs to <ejabberd@process-one.net>. # Report bugs to <ejabberd@process-one.net>.
# #
@ -552,8 +552,8 @@ MAKEFLAGS=
# Identity of this package. # Identity of this package.
PACKAGE_NAME='ejabberd' PACKAGE_NAME='ejabberd'
PACKAGE_TARNAME='ejabberd' PACKAGE_TARNAME='ejabberd'
PACKAGE_VERSION='2.1.x' PACKAGE_VERSION='2.1.5'
PACKAGE_STRING='ejabberd 2.1.x' PACKAGE_STRING='ejabberd 2.1.5'
PACKAGE_BUGREPORT='ejabberd@process-one.net' PACKAGE_BUGREPORT='ejabberd@process-one.net'
PACKAGE_URL='' PACKAGE_URL=''
@ -1278,7 +1278,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing. # Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF cat <<_ACEOF
\`configure' configures ejabberd 2.1.x to adapt to many kinds of systems. \`configure' configures ejabberd 2.1.5 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]... Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1344,7 +1344,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in case $ac_init_help in
short | recursive ) echo "Configuration of ejabberd 2.1.x:";; short | recursive ) echo "Configuration of ejabberd 2.1.5:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
@ -1469,7 +1469,7 @@ fi
test -n "$ac_init_help" && exit $ac_status test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
ejabberd configure 2.1.x ejabberd configure 2.1.5
generated by GNU Autoconf 2.65 generated by GNU Autoconf 2.65
Copyright (C) 2009 Free Software Foundation, Inc. Copyright (C) 2009 Free Software Foundation, Inc.
@ -1815,7 +1815,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. running configure, to aid debugging if configure makes a mistake.
It was created by ejabberd $as_me 2.1.x, which was It was created by ejabberd $as_me 2.1.5, which was
generated by GNU Autoconf 2.65. Invocation command line was generated by GNU Autoconf 2.65. Invocation command line was
$ $0 $@ $ $0 $@
@ -5654,7 +5654,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their # report actual input values of CONFIG_FILES etc. instead of their
# values after options handling. # values after options handling.
ac_log=" ac_log="
This file was extended by ejabberd $as_me 2.1.x, which was This file was extended by ejabberd $as_me 2.1.5, which was
generated by GNU Autoconf 2.65. Invocation command line was generated by GNU Autoconf 2.65. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@ -5707,7 +5707,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\ ac_cs_version="\\
ejabberd config.status 2.1.x ejabberd config.status 2.1.5
configured by $0, generated by GNU Autoconf 2.65, configured by $0, generated by GNU Autoconf 2.65,
with options \\"\$ac_cs_config\\" with options \\"\$ac_cs_config\\"

View File

@ -2,7 +2,7 @@
{application, ejabberd, {application, ejabberd,
[{description, "ejabberd"}, [{description, "ejabberd"},
{vsn, "2.1.x"}, {vsn, "2.1.5"},
{modules, [acl, {modules, [acl,
adhoc, adhoc,
configure, configure,

View File

@ -106,7 +106,7 @@ commands() ->
desc = "Update the given module, or use the keyword: all", desc = "Update the given module, or use the keyword: all",
module = ?MODULE, function = update, module = ?MODULE, function = update,
args = [{module, string}], args = [{module, string}],
result = {res, rescode}}, result = {res, restuple}},
#ejabberd_commands{name = register, tags = [accounts], #ejabberd_commands{name = register, tags = [accounts],
desc = "Register a user", desc = "Register a user",
@ -305,7 +305,10 @@ update(ModStr) ->
update_module(ModuleNameString) -> update_module(ModuleNameString) ->
ModuleName = list_to_atom(ModuleNameString), ModuleName = list_to_atom(ModuleNameString),
ejabberd_update:update([ModuleName]). case ejabberd_update:update([ModuleName]) of
{ok, Res} -> {ok, io_lib:format("Updated: ~p", [Res])};
{error, Reason} -> {error, Reason}
end.
%%% %%%
%%% Account management %%% Account management

View File

@ -57,6 +57,8 @@ start(normal, _Args) ->
ejabberd_config:start(), ejabberd_config:start(),
ejabberd_check:config(), ejabberd_check:config(),
connect_nodes(), connect_nodes(),
%% Loading ASN.1 driver explicitly to avoid races in LDAP
catch asn1rt:load_driver(),
Sup = ejabberd_sup:start_link(), Sup = ejabberd_sup:start_link(),
ejabberd_rdbms:start(), ejabberd_rdbms:start(),
ejabberd_auth:start(), ejabberd_auth:start(),

View File

@ -290,7 +290,7 @@ get_last_info(User, Server) ->
case get_mod_last_enabled(Server) of case get_mod_last_enabled(Server) of
mod_last -> mod_last:get_last_info(User, Server); mod_last -> mod_last:get_last_info(User, Server);
mod_last_odbc -> mod_last_odbc:get_last_info(User, Server); mod_last_odbc -> mod_last_odbc:get_last_info(User, Server);
mod_mod_last -> mod_last_required no_mod_last -> mod_last_required
end. end.
%% @spec (Server) -> mod_last | mod_last_odbc | no_mod_last %% @spec (Server) -> mod_last | mod_last_odbc | no_mod_last

View File

@ -198,7 +198,8 @@ init([From, Server, Type]) ->
open_socket(init, StateData) -> open_socket(init, StateData) ->
log_s2s_out(StateData#state.new, log_s2s_out(StateData#state.new,
StateData#state.myname, StateData#state.myname,
StateData#state.server), StateData#state.server,
StateData#state.tls),
?DEBUG("open_socket: ~p", [{StateData#state.myname, ?DEBUG("open_socket: ~p", [{StateData#state.myname,
StateData#state.server, StateData#state.server,
StateData#state.new, StateData#state.new,
@ -346,8 +347,8 @@ wait_for_validation({xmlstreamelement, El}, StateData) ->
case Type of case Type of
"valid" -> "valid" ->
send_queue(StateData, StateData#state.queue), send_queue(StateData, StateData#state.queue),
?INFO_MSG("Connection established: ~s -> ~s", ?INFO_MSG("Connection established: ~s -> ~s with TLS=~p",
[StateData#state.myname, StateData#state.server]), [StateData#state.myname, StateData#state.server, StateData#state.tls_enabled]),
ejabberd_hooks:run(s2s_connect_hook, ejabberd_hooks:run(s2s_connect_hook,
[StateData#state.myname, [StateData#state.myname,
StateData#state.server]), StateData#state.server]),
@ -1160,10 +1161,10 @@ outgoing_s2s_timeout() ->
%% Human readable S2S logging: Log only new outgoing connections as INFO %% Human readable S2S logging: Log only new outgoing connections as INFO
%% Do not log dialback %% Do not log dialback
log_s2s_out(false, _, _) -> ok; log_s2s_out(false, _, _, _) -> ok;
%% Log new outgoing connections: %% Log new outgoing connections:
log_s2s_out(_, Myname, Server) -> log_s2s_out(_, Myname, Server, Tls) ->
?INFO_MSG("Trying to open s2s connection: ~s -> ~s",[Myname, Server]). ?INFO_MSG("Trying to open s2s connection: ~s -> ~s with TLS=~p", [Myname, Server, Tls]).
%% Calculate timeout depending on which state we are in: %% Calculate timeout depending on which state we are in:
%% Can return integer > 0 | infinity %% Can return integer > 0 | infinity

View File

@ -43,16 +43,29 @@
-define(CALL_TIMEOUT, 10000). % Timeout is in milliseconds: 10 seconds == 10000 -define(CALL_TIMEOUT, 10000). % Timeout is in milliseconds: 10 seconds == 10000
start(Host, ExtPrg) -> start(Host, ExtPrg) ->
spawn(?MODULE, init, [Host, ExtPrg]). lists:foreach(
fun(This) ->
spawn(?MODULE, init, [get_process_name(Host, This), ExtPrg])
end,
lists:seq(0, get_instances(Host)-1)
).
init(Host, ExtPrg) -> init(ProcessName, ExtPrg) ->
register(gen_mod:get_module_proc(Host, eauth), self()), register(ProcessName, self()),
process_flag(trap_exit,true), process_flag(trap_exit,true),
Port = open_port({spawn, ExtPrg}, [{packet,2}]), Port = open_port({spawn, ExtPrg}, [{packet,2}]),
loop(Port, ?INIT_TIMEOUT). loop(Port, ?INIT_TIMEOUT).
stop(Host) -> stop(Host) ->
gen_mod:get_module_proc(Host, eauth) ! stop. lists:foreach(
fun(This) ->
get_process_name(Host, This) ! stop
end,
lists:seq(0, get_instances(Host)-1)
).
get_process_name(Host, Integer) ->
gen_mod:get_module_proc(lists:append([Host, integer_to_list(Integer)]), eauth).
check_password(User, Server, Password) -> check_password(User, Server, Password) ->
call_port(Server, ["auth", User, Server, Password]). call_port(Server, ["auth", User, Server, Password]).
@ -77,12 +90,24 @@ remove_user(User, Server, Password) ->
call_port(Server, Msg) -> call_port(Server, Msg) ->
LServer = jlib:nameprep(Server), LServer = jlib:nameprep(Server),
gen_mod:get_module_proc(LServer, eauth) ! {call, self(), Msg}, ProcessName = get_process_name(LServer, random_instance(get_instances(LServer))),
ProcessName ! {call, self(), Msg},
receive receive
{eauth,Result} -> {eauth,Result} ->
Result Result
end. end.
random_instance(MaxNum) ->
{A1,A2,A3} = now(),
random:seed(A1, A2, A3),
random:uniform(MaxNum) - 1.
get_instances(Server) ->
case ejabberd_config:get_local_option({extauth_instances, Server}) of
Num when is_integer(Num) -> Num;
_ -> 1
end.
loop(Port, Timeout) -> loop(Port, Timeout) ->
receive receive
{call, Caller, Msg} -> {call, Caller, Msg} ->

View File

@ -73,8 +73,7 @@
disco_sm_items/5 disco_sm_items/5
]). ]).
%% exported iq handlers %% exported iq handlers
-export([iq_local/3, -export([iq_sm/3
iq_sm/3
]). ]).
%% exports for console debug manual use %% exports for console debug manual use
@ -198,24 +197,22 @@ init([ServerHost, Opts]) ->
ets:insert(gen_mod:get_module_proc(ServerHost, config), {ignore_pep_from_offline, PepOffline}), ets:insert(gen_mod:get_module_proc(ServerHost, config), {ignore_pep_from_offline, PepOffline}),
ets:insert(gen_mod:get_module_proc(ServerHost, config), {host, Host}), ets:insert(gen_mod:get_module_proc(ServerHost, config), {host, Host}),
ejabberd_hooks:add(sm_remove_connection_hook, ServerHost, ?MODULE, on_user_offline, 75), ejabberd_hooks:add(sm_remove_connection_hook, ServerHost, ?MODULE, on_user_offline, 75),
ejabberd_hooks:add(disco_sm_identity, ServerHost, ?MODULE, disco_sm_identity, 75), ejabberd_hooks:add(disco_local_identity, ServerHost, ?MODULE, disco_local_identity, 75),
ejabberd_hooks:add(disco_sm_features, ServerHost, ?MODULE, disco_sm_features, 75), ejabberd_hooks:add(disco_local_features, ServerHost, ?MODULE, disco_local_features, 75),
ejabberd_hooks:add(disco_sm_items, ServerHost, ?MODULE, disco_sm_items, 75), ejabberd_hooks:add(disco_local_items, ServerHost, ?MODULE, disco_local_items, 75),
ejabberd_hooks:add(presence_probe_hook, ServerHost, ?MODULE, presence_probe, 80), ejabberd_hooks:add(presence_probe_hook, ServerHost, ?MODULE, presence_probe, 80),
ejabberd_hooks:add(roster_in_subscription, ServerHost, ?MODULE, in_subscription, 50), ejabberd_hooks:add(roster_in_subscription, ServerHost, ?MODULE, in_subscription, 50),
ejabberd_hooks:add(roster_out_subscription, ServerHost, ?MODULE, out_subscription, 50), ejabberd_hooks:add(roster_out_subscription, ServerHost, ?MODULE, out_subscription, 50),
ejabberd_hooks:add(remove_user, ServerHost, ?MODULE, remove_user, 50), ejabberd_hooks:add(remove_user, ServerHost, ?MODULE, remove_user, 50),
ejabberd_hooks:add(anonymous_purge_hook, ServerHost, ?MODULE, remove_user, 50), ejabberd_hooks:add(anonymous_purge_hook, ServerHost, ?MODULE, remove_user, 50),
gen_iq_handler:add_iq_handler(ejabberd_sm, ServerHost, ?NS_PUBSUB, ?MODULE, iq_sm, IQDisc),
gen_iq_handler:add_iq_handler(ejabberd_sm, ServerHost, ?NS_PUBSUB_OWNER, ?MODULE, iq_sm, IQDisc),
case lists:member(?PEPNODE, Plugins) of case lists:member(?PEPNODE, Plugins) of
true -> true ->
ejabberd_hooks:add(feature_check_packet, ServerHost, ?MODULE, feature_check_packet, 75), ejabberd_hooks:add(feature_check_packet, ServerHost, ?MODULE, feature_check_packet, 75),
ejabberd_hooks:add(disco_local_identity, ServerHost, ?MODULE, disco_local_identity, 75), ejabberd_hooks:add(disco_sm_identity, ServerHost, ?MODULE, disco_sm_identity, 75),
ejabberd_hooks:add(disco_local_features, ServerHost, ?MODULE, disco_local_features, 75), ejabberd_hooks:add(disco_sm_features, ServerHost, ?MODULE, disco_sm_features, 75),
ejabberd_hooks:add(disco_local_items, ServerHost, ?MODULE, disco_local_items, 75), ejabberd_hooks:add(disco_sm_items, ServerHost, ?MODULE, disco_sm_items, 75),
gen_iq_handler:add_iq_handler(ejabberd_local, ServerHost, ?NS_PUBSUB, ?MODULE, iq_local, IQDisc), gen_iq_handler:add_iq_handler(ejabberd_sm, ServerHost, ?NS_PUBSUB, ?MODULE, iq_sm, IQDisc),
gen_iq_handler:add_iq_handler(ejabberd_local, ServerHost, ?NS_PUBSUB_OWNER, ?MODULE, iq_local, IQDisc); gen_iq_handler:add_iq_handler(ejabberd_sm, ServerHost, ?NS_PUBSUB_OWNER, ?MODULE, iq_sm, IQDisc);
false -> false ->
ok ok
end, end,
@ -584,15 +581,12 @@ send_loop(State) ->
%% disco hooks handling functions %% disco hooks handling functions
%% %%
identity(Host) ->
Identity = case lists:member(?PEPNODE, plugins(Host)) of
true -> [{"category", "pubsub"}, {"type", "pep"}];
false -> [{"category", "pubsub"}, {"type", "service"}]
end,
{xmlelement, "identity", Identity, []}.
disco_local_identity(Acc, _From, To, [], _Lang) -> disco_local_identity(Acc, _From, To, [], _Lang) ->
Acc ++ [identity(To#jid.lserver)]; case lists:member(?PEPNODE, plugins(To#jid.lserver)) of
true ->
[{xmlelement, "identity", [{"category", "pubsub"}, {"type", "pep"}], []} | Acc];
false -> Acc
end;
disco_local_identity(Acc, _From, _To, _Node, _Lang) -> disco_local_identity(Acc, _From, _To, _Node, _Lang) ->
Acc. Acc.
@ -613,76 +607,116 @@ disco_local_items(Acc, _From, _To, [], _Lang) ->
disco_local_items(Acc, _From, _To, _Node, _Lang) -> disco_local_items(Acc, _From, _To, _Node, _Lang) ->
Acc. Acc.
disco_sm_identity(Acc, _From, To, [], _Lang) -> disco_sm_identity(Acc, From, To, Node, Lang) when is_list(Node) ->
Acc ++ [identity(To#jid.lserver)]; disco_sm_identity(Acc, From, To, list_to_binary(Node), Lang);
disco_sm_identity(empty, From, To, Node, Lang) ->
disco_sm_identity([], From, To, Node, Lang);
disco_sm_identity(Acc, From, To, Node, _Lang) -> disco_sm_identity(Acc, From, To, Node, _Lang) ->
LOwner = jlib:jid_tolower(jlib:jid_remove_resource(To)), disco_identity(jlib:jid_tolower(jlib:jid_remove_resource(To)), Node, From) ++ Acc.
Acc ++ case node_disco_identity(LOwner, From, Node) of
{result, I} -> I;
_ -> []
end.
disco_sm_features(Acc, _From, _To, [], _Lang) -> disco_identity(_Host, <<>>, _From) ->
Acc; [{xmlelement, "identity", [{"category", "pubsub"}, {"type", "pep"}], []}];
disco_sm_features(Acc, From, To, Node, _Lang) -> disco_identity(Host, Node, From) ->
LOwner = jlib:jid_tolower(jlib:jid_remove_resource(To)), Action = fun(#pubsub_node{id = Idx, type = Type, options = Options, owners = Owners}) ->
Features = node_disco_features(LOwner, From, Node), case get_allowed_items_call(Host, Idx, From, Type, Options, Owners) of
case {Acc, Features} of {result, _} ->
{{result, AccFeatures}, {result, AddFeatures}} -> {result, [{xmlelement, "identity", [{"category", "pubsub"}, {"type", "pep"}], []},
{result, AccFeatures++AddFeatures}; {xmlelement, "identity",
{_, {result, AddFeatures}} -> [{"category", "pubsub"},
{result, AddFeatures}; {"type", "leaf"}
{_, _} -> | case get_option(Options, title) of
Acc false -> [];
[Title] -> [{"name", Title}]
end],
[]}]};
_ -> {result, []}
end
end,
case transaction(Host, Node, Action, sync_dirty) of
{result, {_, Result}} -> Result;
_ -> []
end. end.
disco_sm_items(Acc, From, To, [], _Lang) -> disco_sm_features(Acc, From, To, Node, Lang) when is_list(Node) ->
Host = To#jid.lserver, disco_sm_features(Acc, From, To, list_to_binary(Node), Lang);
case tree_action(Host, get_subnodes, [Host, <<>>, From]) of disco_sm_features(empty, From, To, Node, Lang) ->
[] -> disco_sm_features({result, []}, From, To, Node, Lang);
Acc; disco_sm_features({result, OtherFeatures} = _Acc, From, To, Node, _Lang) ->
Nodes -> {result,
SBJID = jlib:jid_to_string(jlib:jid_remove_resource(To)), OtherFeatures ++
Items = case Acc of disco_features(jlib:jid_tolower(jlib:jid_remove_resource(To)), Node, From)};
{result, I} -> I; disco_sm_features(Acc, _From, _To, _Node, _Lang) ->
_ -> [] Acc.
end,
NodeItems = lists:map( disco_features(_Host, <<>>, _From) ->
fun(#pubsub_node{nodeid = {_, Node}}) -> [?NS_PUBSUB
{xmlelement, "item", | [?NS_PUBSUB++"#"++Feature || Feature <- features("pep")]];
[{"jid", SBJID}|nodeAttr(Node)], disco_features(Host, Node, From) ->
[]} Action = fun(#pubsub_node{id = Idx, type = Type, options = Options, owners = Owners}) ->
end, Nodes), case get_allowed_items_call(Host, Idx, From, Type, Options, Owners) of
{result, NodeItems ++ Items} {result, _} ->
{result, [?NS_PUBSUB
| [?NS_PUBSUB ++ "#" ++ Feature || Feature <- features("pep")]]};
_ -> {result, []}
end
end,
case transaction(Host, Node, Action, sync_dirty) of
{result, {_, Result}} -> Result;
_ -> []
end.
disco_sm_items(Acc, From, To, Node, Lang) when is_list(Node) ->
disco_sm_items(Acc, From, To, list_to_binary(Node), Lang);
disco_sm_items(empty, From, To, Node, Lang) ->
disco_sm_items({result, []}, From, To, Node, Lang);
disco_sm_items({result, OtherItems}, From, To, Node, _Lang) ->
{result,
lists:usort(OtherItems ++
disco_items(jlib:jid_tolower(jlib:jid_remove_resource(To)), Node, From))};
disco_sm_items(Acc, _From, _To, _Node, _Lang) ->
Acc.
disco_items(Host, <<>>, From) ->
Action = fun(#pubsub_node{nodeid ={_, NodeID}, options = Options, type = Type, id = Idx, owners = Owners}, Acc) ->
case get_allowed_items_call(Host, Idx, From, Type, Options, Owners) of
{result, _} ->
[{xmlelement, "item",
[{"node", binary_to_list(NodeID)},
{"jid", case Host of
{_,_,_} -> jlib:jid_to_string(Host);
_Host -> Host
end}
| case get_option(Options, title) of
false -> [];
[Title] -> [{"name", Title}]
end],
[]}
| Acc];
_ -> Acc
end
end,
case transaction(Host, Action, sync_dirty) of
{result, Items} -> Items;
_ -> []
end; end;
disco_sm_items(Acc, From, To, SNode, _Lang) -> disco_items(Host, Node, From) ->
Host = To#jid.lserver, Action = fun(#pubsub_node{id = Idx, type = Type, options = Options, owners = Owners}) ->
Node = string_to_node(SNode), case get_allowed_items_call(Host, Idx, From, Type, Options, Owners) of
Action = fun(#pubsub_node{type = Type, id = NodeId}) -> {result, Items} ->
% TODO call get_items/6 instead for access control (EJAB-1033) {result, [{xmlelement, "item",
case node_call(Type, get_items, [NodeId, From]) of [{"jid", case Host of
{result, []} -> {_,_,_} -> jlib:jid_to_string(Host);
none; _Host -> Host
{result, AllItems} -> end},
SBJID = jlib:jid_to_string(jlib:jid_remove_resource(To)), {"name", ItemID}], []}
Items = case Acc of || #pubsub_item{itemid = {ItemID,_}} <- Items]};
{result, I} -> I; _ -> {result, []}
_ -> [] end
end, end,
NodeItems = lists:map(
fun(#pubsub_item{itemid = {Id, _}}) ->
{result, Name} = node_call(Type, get_item_name, [Host, Node, Id]),
{xmlelement, "item", [{"jid", SBJID}, {"name", Name}], []}
end, AllItems),
{result, NodeItems ++ Items};
_ ->
none
end
end,
case transaction(Host, Node, Action, sync_dirty) of case transaction(Host, Node, Action, sync_dirty) of
{result, {_, Items}} -> {result, Items}; {result, {_, Result}} -> Result;
_ -> Acc _ -> []
end. end.
%% ------- %% -------
@ -858,25 +892,23 @@ terminate(_Reason, #state{host = Host,
case lists:member(?PEPNODE, Plugins) of case lists:member(?PEPNODE, Plugins) of
true -> true ->
ejabberd_hooks:delete(feature_check_packet, ServerHost, ?MODULE, feature_check_packet, 75), ejabberd_hooks:delete(feature_check_packet, ServerHost, ?MODULE, feature_check_packet, 75),
ejabberd_hooks:delete(disco_local_identity, ServerHost, ?MODULE, disco_local_identity, 75), ejabberd_hooks:delete(disco_sm_identity, ServerHost, ?MODULE, disco_sm_identity, 75),
ejabberd_hooks:delete(disco_local_features, ServerHost, ?MODULE, disco_local_features, 75), ejabberd_hooks:delete(disco_sm_features, ServerHost, ?MODULE, disco_sm_features, 75),
ejabberd_hooks:delete(disco_local_items, ServerHost, ?MODULE, disco_local_items, 75), ejabberd_hooks:delete(disco_sm_items, ServerHost, ?MODULE, disco_sm_items, 75),
gen_iq_handler:remove_iq_handler(ejabberd_local, ServerHost, ?NS_PUBSUB), gen_iq_handler:remove_iq_handler(ejabberd_sm, ServerHost, ?NS_PUBSUB),
gen_iq_handler:remove_iq_handler(ejabberd_local, ServerHost, ?NS_PUBSUB_OWNER); gen_iq_handler:remove_iq_handler(ejabberd_sm, ServerHost, ?NS_PUBSUB_OWNER);
false -> false ->
ok ok
end, end,
ejabberd_hooks:delete(sm_remove_connection_hook, ServerHost, ?MODULE, on_user_offline, 75), ejabberd_hooks:delete(sm_remove_connection_hook, ServerHost, ?MODULE, on_user_offline, 75),
ejabberd_hooks:delete(disco_sm_identity, ServerHost, ?MODULE, disco_sm_identity, 75), ejabberd_hooks:delete(disco_local_identity, ServerHost, ?MODULE, disco_local_identity, 75),
ejabberd_hooks:delete(disco_sm_features, ServerHost, ?MODULE, disco_sm_features, 75), ejabberd_hooks:delete(disco_local_features, ServerHost, ?MODULE, disco_local_features, 75),
ejabberd_hooks:delete(disco_sm_items, ServerHost, ?MODULE, disco_sm_items, 75), ejabberd_hooks:delete(disco_local_items, ServerHost, ?MODULE, disco_local_items, 75),
ejabberd_hooks:delete(presence_probe_hook, ServerHost, ?MODULE, presence_probe, 80), ejabberd_hooks:delete(presence_probe_hook, ServerHost, ?MODULE, presence_probe, 80),
ejabberd_hooks:delete(roster_in_subscription, ServerHost, ?MODULE, in_subscription, 50), ejabberd_hooks:delete(roster_in_subscription, ServerHost, ?MODULE, in_subscription, 50),
ejabberd_hooks:delete(roster_out_subscription, ServerHost, ?MODULE, out_subscription, 50), ejabberd_hooks:delete(roster_out_subscription, ServerHost, ?MODULE, out_subscription, 50),
ejabberd_hooks:delete(remove_user, ServerHost, ?MODULE, remove_user, 50), ejabberd_hooks:delete(remove_user, ServerHost, ?MODULE, remove_user, 50),
ejabberd_hooks:delete(anonymous_purge_hook, ServerHost, ?MODULE, remove_user, 50), ejabberd_hooks:delete(anonymous_purge_hook, ServerHost, ?MODULE, remove_user, 50),
gen_iq_handler:remove_iq_handler(ejabberd_sm, ServerHost, ?NS_PUBSUB),
gen_iq_handler:remove_iq_handler(ejabberd_sm, ServerHost, ?NS_PUBSUB_OWNER),
mod_disco:unregister_feature(ServerHost, ?NS_PUBSUB), mod_disco:unregister_feature(ServerHost, ?NS_PUBSUB),
gen_mod:get_module_proc(ServerHost, ?LOOPNAME) ! stop, gen_mod:get_module_proc(ServerHost, ?LOOPNAME) ! stop,
terminate_plugins(Host, ServerHost, Plugins, TreePlugin). terminate_plugins(Host, ServerHost, Plugins, TreePlugin).
@ -1017,10 +1049,10 @@ command_disco_info(_Host, <<?NS_PUBSUB_GET_PENDING>>, _From) ->
node_disco_info(Host, Node, From) -> node_disco_info(Host, Node, From) ->
node_disco_info(Host, Node, From, true, true). node_disco_info(Host, Node, From, true, true).
node_disco_identity(Host, Node, From) -> %node_disco_identity(Host, Node, From) ->
node_disco_info(Host, Node, From, true, false). % node_disco_info(Host, Node, From, true, false).
node_disco_features(Host, Node, From) -> %node_disco_features(Host, Node, From) ->
node_disco_info(Host, Node, From, false, true). % node_disco_info(Host, Node, From, false, true).
node_disco_info(Host, Node, From, Identity, Features) -> node_disco_info(Host, Node, From, Identity, Features) ->
Action = Action =
fun(#pubsub_node{type = Type, id = NodeId}) -> fun(#pubsub_node{type = Type, id = NodeId}) ->
@ -1120,17 +1152,15 @@ iq_disco_items(Host, Item, From) ->
{result, []}; {result, []};
[SNode] -> [SNode] ->
Node = string_to_node(SNode), Node = string_to_node(SNode),
Action = Action = fun(#pubsub_node{id = Idx, type = Type, options = Options, owners = Owners}) ->
fun(#pubsub_node{type = Type, id = NodeId}) -> NodeItems = case get_allowed_items_call(Host, Idx, From, Type, Options, Owners) of
% TODO call get_items/6 instead for access control (EJAB-1033) {result, R} -> R;
NodeItems = case node_call(Type, get_items, [NodeId, From]) of _ -> []
{result, I} -> I; end,
_ -> []
end,
Nodes = lists:map( Nodes = lists:map(
fun(#pubsub_node{nodeid = {_, SubNode}, options = Options}) -> fun(#pubsub_node{nodeid = {_, SubNode}, options = SubOptions}) ->
Attrs = Attrs =
case get_option(Options, title) of case get_option(SubOptions, title) of
false -> false ->
[{"jid", Host} |nodeAttr(SubNode)]; [{"jid", Host} |nodeAttr(SubNode)];
Title -> Title ->
@ -1151,24 +1181,6 @@ iq_disco_items(Host, Item, From) ->
end end
end. end.
iq_local(From, To, #iq{type = Type, sub_el = SubEl, xmlns = XMLNS, lang = Lang} = IQ) ->
ServerHost = To#jid.lserver,
%% Accept IQs to server only from our own users.
if
From#jid.lserver /= ServerHost ->
IQ#iq{type = error, sub_el = [?ERR_FORBIDDEN, SubEl]};
true ->
LOwner = jlib:jid_tolower(jlib:jid_remove_resource(From)),
Res = case XMLNS of
?NS_PUBSUB -> iq_pubsub(LOwner, ServerHost, From, Type, SubEl, Lang);
?NS_PUBSUB_OWNER -> iq_pubsub_owner(LOwner, ServerHost, From, Type, SubEl, Lang)
end,
case Res of
{result, IQRes} -> IQ#iq{type = result, sub_el = IQRes};
{error, Error} -> IQ#iq{type = error, sub_el = [Error, SubEl]}
end
end.
iq_sm(From, To, #iq{type = Type, sub_el = SubEl, xmlns = XMLNS, lang = Lang} = IQ) -> iq_sm(From, To, #iq{type = Type, sub_el = SubEl, xmlns = XMLNS, lang = Lang} = IQ) ->
ServerHost = To#jid.lserver, ServerHost = To#jid.lserver,
LOwner = jlib:jid_tolower(jlib:jid_remove_resource(To)), LOwner = jlib:jid_tolower(jlib:jid_remove_resource(To)),
@ -1868,7 +1880,7 @@ subscribe_node(Host, Node, From, JID, Configuration) ->
error -> {"", "", ""}; error -> {"", "", ""};
J -> jlib:jid_tolower(J) J -> jlib:jid_tolower(J)
end, end,
Action = fun(#pubsub_node{options = Options, owners = [Owner|_], type = Type, id = NodeId}) -> Action = fun(#pubsub_node{options = Options, owners = Owners, type = Type, id = NodeId}) ->
Features = features(Type), Features = features(Type),
SubscribeFeature = lists:member("subscribe", Features), SubscribeFeature = lists:member("subscribe", Features),
OptionsFeature = lists:member("subscription-options", Features), OptionsFeature = lists:member("subscription-options", Features),
@ -1877,21 +1889,7 @@ subscribe_node(Host, Node, From, JID, Configuration) ->
AccessModel = get_option(Options, access_model), AccessModel = get_option(Options, access_model),
SendLast = get_option(Options, send_last_published_item), SendLast = get_option(Options, send_last_published_item),
AllowedGroups = get_option(Options, roster_groups_allowed, []), AllowedGroups = get_option(Options, roster_groups_allowed, []),
{PresenceSubscription, RosterGroup} = {PresenceSubscription, RosterGroup} = get_presence_and_roster_permissions(Host, Subscriber, Owners, AccessModel, AllowedGroups),
case Host of
{OUser, OServer, _} ->
get_roster_info(OUser, OServer,
Subscriber, AllowedGroups);
_ ->
case Subscriber of
{"", "", ""} ->
{false, false};
_ ->
{OU, OS, _} = Owner,
get_roster_info(OU, OS,
Subscriber, AllowedGroups)
end
end,
if if
not SubscribeFeature -> not SubscribeFeature ->
%% Node does not support subscriptions %% Node does not support subscriptions
@ -2234,20 +2232,13 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) ->
{error, Error} -> {error, Error} ->
{error, Error}; {error, Error};
_ -> _ ->
Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId}) -> Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId, owners = Owners}) ->
Features = features(Type), Features = features(Type),
RetreiveFeature = lists:member("retrieve-items", Features), RetreiveFeature = lists:member("retrieve-items", Features),
PersistentFeature = lists:member("persistent-items", Features), PersistentFeature = lists:member("persistent-items", Features),
AccessModel = get_option(Options, access_model), AccessModel = get_option(Options, access_model),
AllowedGroups = get_option(Options, roster_groups_allowed, []), AllowedGroups = get_option(Options, roster_groups_allowed, []),
{PresenceSubscription, RosterGroup} = {PresenceSubscription, RosterGroup} = get_presence_and_roster_permissions(Host, From, Owners, AccessModel, AllowedGroups),
case Host of
{OUser, OServer, _} ->
get_roster_info(OUser, OServer,
jlib:jid_tolower(From), AllowedGroups);
_ ->
{true, true}
end,
if if
not RetreiveFeature -> not RetreiveFeature ->
%% Item Retrieval Not Supported %% Item Retrieval Not Supported
@ -2297,6 +2288,12 @@ get_item(Host, Node, ItemId) ->
{result, {_, Items}} -> Items; {result, {_, Items}} -> Items;
Error -> Error Error -> Error
end. end.
get_allowed_items_call(Host, NodeIdx, From, Type, Options, Owners) ->
AccessModel = get_option(Options, access_model),
AllowedGroups = get_option(Options, roster_groups_allowed, []),
{PresenceSubscription, RosterGroup} = get_presence_and_roster_permissions(Host, From, Owners, AccessModel, AllowedGroups),
node_call(Type, get_items, [NodeIdx, From, AccessModel, PresenceSubscription, RosterGroup, undefined]).
%% @spec (Host, Node, NodeId, Type, LJID, Number) -> any() %% @spec (Host, Node, NodeId, Type, LJID, Number) -> any()
%% Host = pubsubHost() %% Host = pubsubHost()
@ -2774,8 +2771,24 @@ set_subscriptions(Host, Node, From, EntitiesEls) ->
end end
end. end.
get_presence_and_roster_permissions(Host, From, Owners, AccessModel, AllowedGroups) ->
if (AccessModel == presence) or (AccessModel == roster) ->
case Host of
{User, Server, _} ->
get_roster_info(User, Server, From, AllowedGroups);
_ ->
[{OUser, OServer, _}|_] = Owners,
get_roster_info(OUser, OServer, From, AllowedGroups)
end;
true ->
{true, true}
end.
%% @spec (OwnerUser, OwnerServer, {SubscriberUser, SubscriberServer, SubscriberResource}, AllowedGroups) %% @spec (OwnerUser, OwnerServer, {SubscriberUser, SubscriberServer, SubscriberResource}, AllowedGroups)
%% -> {PresenceSubscription, RosterGroup} %% -> {PresenceSubscription, RosterGroup}
get_roster_info(_, _, {"", "", _}, _) ->
{false, false};
get_roster_info(OwnerUser, OwnerServer, {SubscriberUser, SubscriberServer, _}, AllowedGroups) -> get_roster_info(OwnerUser, OwnerServer, {SubscriberUser, SubscriberServer, _}, AllowedGroups) ->
{Subscription, Groups} = {Subscription, Groups} =
ejabberd_hooks:run_fold( ejabberd_hooks:run_fold(
@ -2787,7 +2800,9 @@ get_roster_info(OwnerUser, OwnerServer, {SubscriberUser, SubscriberServer, _}, A
RosterGroup = lists:any(fun(Group) -> RosterGroup = lists:any(fun(Group) ->
lists:member(Group, AllowedGroups) lists:member(Group, AllowedGroups)
end, Groups), end, Groups),
{PresenceSubscription, RosterGroup}. {PresenceSubscription, RosterGroup};
get_roster_info(OwnerUser, OwnerServer, JID, AllowedGroups) ->
get_roster_info(OwnerUser, OwnerServer, jlib:jid_tolower(JID), AllowedGroups).
%% @spec (AffiliationStr) -> Affiliation %% @spec (AffiliationStr) -> Affiliation
%% AffiliationStr = string() %% AffiliationStr = string()
@ -3742,6 +3757,10 @@ transaction(Host, Node, Action, Trans) ->
Error Error
end end
end, Trans). end, Trans).
transaction(Host, Action, Trans) ->
transaction(fun() ->
{result, lists:foldl(Action, [], tree_call(Host, get_nodes, [Host]))}
end, Trans).
transaction(Fun, Trans) -> transaction(Fun, Trans) ->
case catch mnesia:Trans(Fun) of case catch mnesia:Trans(Fun) of

View File

@ -73,8 +73,7 @@
disco_sm_items/5 disco_sm_items/5
]). ]).
%% exported iq handlers %% exported iq handlers
-export([iq_local/3, -export([iq_sm/3
iq_sm/3
]). ]).
%% exports for console debug manual use %% exports for console debug manual use
@ -198,24 +197,22 @@ init([ServerHost, Opts]) ->
ets:insert(gen_mod:get_module_proc(ServerHost, config), {ignore_pep_from_offline, PepOffline}), ets:insert(gen_mod:get_module_proc(ServerHost, config), {ignore_pep_from_offline, PepOffline}),
ets:insert(gen_mod:get_module_proc(ServerHost, config), {host, Host}), ets:insert(gen_mod:get_module_proc(ServerHost, config), {host, Host}),
ejabberd_hooks:add(sm_remove_connection_hook, ServerHost, ?MODULE, on_user_offline, 75), ejabberd_hooks:add(sm_remove_connection_hook, ServerHost, ?MODULE, on_user_offline, 75),
ejabberd_hooks:add(disco_sm_identity, ServerHost, ?MODULE, disco_sm_identity, 75), ejabberd_hooks:add(disco_local_identity, ServerHost, ?MODULE, disco_local_identity, 75),
ejabberd_hooks:add(disco_sm_features, ServerHost, ?MODULE, disco_sm_features, 75), ejabberd_hooks:add(disco_local_features, ServerHost, ?MODULE, disco_local_features, 75),
ejabberd_hooks:add(disco_sm_items, ServerHost, ?MODULE, disco_sm_items, 75), ejabberd_hooks:add(disco_local_items, ServerHost, ?MODULE, disco_local_items, 75),
ejabberd_hooks:add(presence_probe_hook, ServerHost, ?MODULE, presence_probe, 80), ejabberd_hooks:add(presence_probe_hook, ServerHost, ?MODULE, presence_probe, 80),
ejabberd_hooks:add(roster_in_subscription, ServerHost, ?MODULE, in_subscription, 50), ejabberd_hooks:add(roster_in_subscription, ServerHost, ?MODULE, in_subscription, 50),
ejabberd_hooks:add(roster_out_subscription, ServerHost, ?MODULE, out_subscription, 50), ejabberd_hooks:add(roster_out_subscription, ServerHost, ?MODULE, out_subscription, 50),
ejabberd_hooks:add(remove_user, ServerHost, ?MODULE, remove_user, 50), ejabberd_hooks:add(remove_user, ServerHost, ?MODULE, remove_user, 50),
ejabberd_hooks:add(anonymous_purge_hook, ServerHost, ?MODULE, remove_user, 50), ejabberd_hooks:add(anonymous_purge_hook, ServerHost, ?MODULE, remove_user, 50),
gen_iq_handler:add_iq_handler(ejabberd_sm, ServerHost, ?NS_PUBSUB, ?MODULE, iq_sm, IQDisc),
gen_iq_handler:add_iq_handler(ejabberd_sm, ServerHost, ?NS_PUBSUB_OWNER, ?MODULE, iq_sm, IQDisc),
case lists:member(?PEPNODE, Plugins) of case lists:member(?PEPNODE, Plugins) of
true -> true ->
ejabberd_hooks:add(feature_check_packet, ServerHost, ?MODULE, feature_check_packet, 75), ejabberd_hooks:add(feature_check_packet, ServerHost, ?MODULE, feature_check_packet, 75),
ejabberd_hooks:add(disco_local_identity, ServerHost, ?MODULE, disco_local_identity, 75), ejabberd_hooks:add(disco_sm_identity, ServerHost, ?MODULE, disco_sm_identity, 75),
ejabberd_hooks:add(disco_local_features, ServerHost, ?MODULE, disco_local_features, 75), ejabberd_hooks:add(disco_sm_features, ServerHost, ?MODULE, disco_sm_features, 75),
ejabberd_hooks:add(disco_local_items, ServerHost, ?MODULE, disco_local_items, 75), ejabberd_hooks:add(disco_sm_items, ServerHost, ?MODULE, disco_sm_items, 75),
gen_iq_handler:add_iq_handler(ejabberd_local, ServerHost, ?NS_PUBSUB, ?MODULE, iq_local, IQDisc), gen_iq_handler:add_iq_handler(ejabberd_sm, ServerHost, ?NS_PUBSUB, ?MODULE, iq_sm, IQDisc),
gen_iq_handler:add_iq_handler(ejabberd_local, ServerHost, ?NS_PUBSUB_OWNER, ?MODULE, iq_local, IQDisc); gen_iq_handler:add_iq_handler(ejabberd_sm, ServerHost, ?NS_PUBSUB_OWNER, ?MODULE, iq_sm, IQDisc);
false -> false ->
ok ok
end, end,
@ -387,15 +384,12 @@ send_loop(State) ->
%% disco hooks handling functions %% disco hooks handling functions
%% %%
identity(Host) ->
Identity = case lists:member(?PEPNODE, plugins(Host)) of
true -> [{"category", "pubsub"}, {"type", "pep"}];
false -> [{"category", "pubsub"}, {"type", "service"}]
end,
{xmlelement, "identity", Identity, []}.
disco_local_identity(Acc, _From, To, [], _Lang) -> disco_local_identity(Acc, _From, To, [], _Lang) ->
Acc ++ [identity(To#jid.lserver)]; case lists:member(?PEPNODE, plugins(To#jid.lserver)) of
true ->
[{xmlelement, "identity", [{"category", "pubsub"}, {"type", "pep"}], []} | Acc];
false -> Acc
end;
disco_local_identity(Acc, _From, _To, _Node, _Lang) -> disco_local_identity(Acc, _From, _To, _Node, _Lang) ->
Acc. Acc.
@ -416,76 +410,120 @@ disco_local_items(Acc, _From, _To, [], _Lang) ->
disco_local_items(Acc, _From, _To, _Node, _Lang) -> disco_local_items(Acc, _From, _To, _Node, _Lang) ->
Acc. Acc.
disco_sm_identity(Acc, _From, To, [], _Lang) -> disco_sm_identity(Acc, From, To, Node, Lang) when is_list(Node) ->
Acc ++ [identity(To#jid.lserver)]; disco_sm_identity(Acc, From, To, list_to_binary(Node), Lang);
disco_sm_identity(empty, From, To, Node, Lang) ->
disco_sm_identity([], From, To, Node, Lang);
disco_sm_identity(Acc, From, To, Node, _Lang) -> disco_sm_identity(Acc, From, To, Node, _Lang) ->
LOwner = jlib:jid_tolower(jlib:jid_remove_resource(To)), disco_identity(jlib:jid_tolower(jlib:jid_remove_resource(To)), Node, From) ++ Acc.
Acc ++ case node_disco_identity(LOwner, From, Node) of
{result, I} -> I;
_ -> []
end.
disco_sm_features(Acc, _From, _To, [], _Lang) -> disco_identity(_Host, <<>>, _From) ->
Acc; [{xmlelement, "identity", [{"category", "pubsub"}, {"type", "pep"}], []}];
disco_sm_features(Acc, From, To, Node, _Lang) -> disco_identity(Host, Node, From) ->
LOwner = jlib:jid_tolower(jlib:jid_remove_resource(To)), Action = fun(#pubsub_node{id = Idx, type = Type, options = Options}) ->
Features = node_disco_features(LOwner, From, Node), Owners = node_owners_call(Type, Idx),
case {Acc, Features} of case get_allowed_items_call(Host, Idx, From, Type, Options, Owners) of
{{result, AccFeatures}, {result, AddFeatures}} -> {result, _} ->
{result, AccFeatures++AddFeatures}; {result, [{xmlelement, "identity", [{"category", "pubsub"}, {"type", "pep"}], []},
{_, {result, AddFeatures}} -> {xmlelement, "identity",
{result, AddFeatures}; [{"category", "pubsub"},
{_, _} -> {"type", "leaf"}
Acc | case get_option(Options, title) of
false -> [];
[Title] -> [{"name", Title}]
end],
[]}]};
_ -> {result, []}
end
end,
case transaction(Host, Node, Action, sync_dirty) of
{result, {_, Result}} -> Result;
_ -> []
end. end.
disco_sm_items(Acc, From, To, [], _Lang) -> disco_sm_features(Acc, From, To, Node, Lang) when is_list(Node) ->
Host = To#jid.lserver, disco_sm_features(Acc, From, To, list_to_binary(Node), Lang);
case tree_action(Host, get_subnodes, [Host, <<>>, From]) of disco_sm_features(empty, From, To, Node, Lang) ->
[] -> disco_sm_features({result, []}, From, To, Node, Lang);
Acc; disco_sm_features({result, OtherFeatures} = _Acc, From, To, Node, _Lang) ->
Nodes -> {result,
SBJID = jlib:jid_to_string(jlib:jid_remove_resource(To)), OtherFeatures ++
Items = case Acc of disco_features(jlib:jid_tolower(jlib:jid_remove_resource(To)), Node, From)};
{result, I} -> I; disco_sm_features(Acc, _From, _To, _Node, _Lang) ->
_ -> [] Acc.
end,
NodeItems = lists:map( disco_features(_Host, <<>>, _From) ->
fun(#pubsub_node{nodeid = {_, Node}}) -> [?NS_PUBSUB
{xmlelement, "item", | [?NS_PUBSUB++"#"++Feature || Feature <- features("pep")]];
[{"jid", SBJID}|nodeAttr(Node)], disco_features(Host, Node, From) ->
[]} Action = fun(#pubsub_node{id = Idx, type = Type, options = Options}) ->
end, Nodes), Owners = node_owners_call(Type, Idx),
{result, NodeItems ++ Items} case get_allowed_items_call(Host, Idx, From, Type, Options, Owners) of
{result, _} ->
{result, [?NS_PUBSUB
| [?NS_PUBSUB ++ "#" ++ Feature || Feature <- features("pep")]]};
_ -> {result, []}
end
end,
case transaction(Host, Node, Action, sync_dirty) of
{result, {_, Result}} -> Result;
_ -> []
end.
disco_sm_items(Acc, From, To, Node, Lang) when is_list(Node) ->
disco_sm_items(Acc, From, To, list_to_binary(Node), Lang);
disco_sm_items(empty, From, To, Node, Lang) ->
disco_sm_items({result, []}, From, To, Node, Lang);
disco_sm_items({result, OtherItems}, From, To, Node, _Lang) ->
{result,
lists:usort(OtherItems ++
disco_items(jlib:jid_tolower(jlib:jid_remove_resource(To)), Node, From))};
disco_sm_items(Acc, _From, _To, _Node, _Lang) ->
Acc.
disco_items(Host, <<>>, From) ->
Action = fun(#pubsub_node{nodeid ={_, NodeID}, options = Options, type = Type, id = Idx}, Acc) ->
Owners = node_owners_call(Type, Idx),
case get_allowed_items_call(Host, Idx, From, Type, Options, Owners) of
{result, _} ->
[{xmlelement, "item",
[{"node", binary_to_list(NodeID)},
{"jid", case Host of
{_,_,_} -> jlib:jid_to_string(Host);
_Host -> Host
end}
| case get_option(Options, title) of
false -> [];
[Title] -> [{"name", Title}]
end],
[]}
| Acc];
_ -> Acc
end
end,
case transaction_on_nodes(Host, Action, sync_dirty) of
{result, Items} -> Items;
_ -> []
end; end;
disco_sm_items(Acc, From, To, SNode, _Lang) -> disco_items(Host, Node, From) ->
Host = To#jid.lserver, Action = fun(#pubsub_node{id = Idx, type = Type, options = Options}) ->
Node = string_to_node(SNode), Owners = node_owners_call(Type, Idx),
Action = fun(#pubsub_node{type = Type, id = NodeId}) -> case get_allowed_items_call(Host, Idx, From, Type, Options, Owners) of
% TODO call get_items/6 instead for access control (EJAB-1033) {result, Items} ->
case node_call(Type, get_items, [NodeId, From]) of {result, [{xmlelement, "item",
{result, []} -> [{"jid", case Host of
none; {_,_,_} -> jlib:jid_to_string(Host);
{result, AllItems} -> _Host -> Host
SBJID = jlib:jid_to_string(jlib:jid_remove_resource(To)), end},
Items = case Acc of {"name", ItemID}], []}
{result, I} -> I; || #pubsub_item{itemid = {ItemID,_}} <- Items]};
_ -> [] _ -> {result, []}
end, end
NodeItems = lists:map( end,
fun(#pubsub_item{itemid = {Id, _}}) ->
{result, Name} = node_call(Type, get_item_name, [Host, Node, Id]),
{xmlelement, "item", [{"jid", SBJID}, {"name", Name}], []}
end, AllItems),
{result, NodeItems ++ Items};
_ ->
none
end
end,
case transaction(Host, Node, Action, sync_dirty) of case transaction(Host, Node, Action, sync_dirty) of
{result, {_, Items}} -> {result, Items}; {result, {_, Result}} -> Result;
_ -> Acc _ -> []
end. end.
%% ------- %% -------
@ -661,25 +699,23 @@ terminate(_Reason, #state{host = Host,
case lists:member(?PEPNODE, Plugins) of case lists:member(?PEPNODE, Plugins) of
true -> true ->
ejabberd_hooks:delete(feature_check_packet, ServerHost, ?MODULE, feature_check_packet, 75), ejabberd_hooks:delete(feature_check_packet, ServerHost, ?MODULE, feature_check_packet, 75),
ejabberd_hooks:delete(disco_local_identity, ServerHost, ?MODULE, disco_local_identity, 75), ejabberd_hooks:delete(disco_sm_identity, ServerHost, ?MODULE, disco_sm_identity, 75),
ejabberd_hooks:delete(disco_local_features, ServerHost, ?MODULE, disco_local_features, 75), ejabberd_hooks:delete(disco_sm_features, ServerHost, ?MODULE, disco_sm_features, 75),
ejabberd_hooks:delete(disco_local_items, ServerHost, ?MODULE, disco_local_items, 75), ejabberd_hooks:delete(disco_sm_items, ServerHost, ?MODULE, disco_sm_items, 75),
gen_iq_handler:remove_iq_handler(ejabberd_local, ServerHost, ?NS_PUBSUB), gen_iq_handler:remove_iq_handler(ejabberd_sm, ServerHost, ?NS_PUBSUB),
gen_iq_handler:remove_iq_handler(ejabberd_local, ServerHost, ?NS_PUBSUB_OWNER); gen_iq_handler:remove_iq_handler(ejabberd_sm, ServerHost, ?NS_PUBSUB_OWNER);
false -> false ->
ok ok
end, end,
ejabberd_hooks:delete(sm_remove_connection_hook, ServerHost, ?MODULE, on_user_offline, 75), ejabberd_hooks:delete(sm_remove_connection_hook, ServerHost, ?MODULE, on_user_offline, 75),
ejabberd_hooks:delete(disco_sm_identity, ServerHost, ?MODULE, disco_sm_identity, 75), ejabberd_hooks:delete(disco_local_identity, ServerHost, ?MODULE, disco_local_identity, 75),
ejabberd_hooks:delete(disco_sm_features, ServerHost, ?MODULE, disco_sm_features, 75), ejabberd_hooks:delete(disco_local_features, ServerHost, ?MODULE, disco_local_features, 75),
ejabberd_hooks:delete(disco_sm_items, ServerHost, ?MODULE, disco_sm_items, 75), ejabberd_hooks:delete(disco_local_items, ServerHost, ?MODULE, disco_local_items, 75),
ejabberd_hooks:delete(presence_probe_hook, ServerHost, ?MODULE, presence_probe, 80), ejabberd_hooks:delete(presence_probe_hook, ServerHost, ?MODULE, presence_probe, 80),
ejabberd_hooks:delete(roster_in_subscription, ServerHost, ?MODULE, in_subscription, 50), ejabberd_hooks:delete(roster_in_subscription, ServerHost, ?MODULE, in_subscription, 50),
ejabberd_hooks:delete(roster_out_subscription, ServerHost, ?MODULE, out_subscription, 50), ejabberd_hooks:delete(roster_out_subscription, ServerHost, ?MODULE, out_subscription, 50),
ejabberd_hooks:delete(remove_user, ServerHost, ?MODULE, remove_user, 50), ejabberd_hooks:delete(remove_user, ServerHost, ?MODULE, remove_user, 50),
ejabberd_hooks:delete(anonymous_purge_hook, ServerHost, ?MODULE, remove_user, 50), ejabberd_hooks:delete(anonymous_purge_hook, ServerHost, ?MODULE, remove_user, 50),
gen_iq_handler:remove_iq_handler(ejabberd_sm, ServerHost, ?NS_PUBSUB),
gen_iq_handler:remove_iq_handler(ejabberd_sm, ServerHost, ?NS_PUBSUB_OWNER),
mod_disco:unregister_feature(ServerHost, ?NS_PUBSUB), mod_disco:unregister_feature(ServerHost, ?NS_PUBSUB),
gen_mod:get_module_proc(ServerHost, ?LOOPNAME) ! stop, gen_mod:get_module_proc(ServerHost, ?LOOPNAME) ! stop,
terminate_plugins(Host, ServerHost, Plugins, TreePlugin). terminate_plugins(Host, ServerHost, Plugins, TreePlugin).
@ -821,10 +857,10 @@ command_disco_info(_Host, <<?NS_PUBSUB_GET_PENDING>>, _From) ->
node_disco_info(Host, Node, From) -> node_disco_info(Host, Node, From) ->
node_disco_info(Host, Node, From, true, true). node_disco_info(Host, Node, From, true, true).
node_disco_identity(Host, Node, From) -> %node_disco_identity(Host, Node, From) ->
node_disco_info(Host, Node, From, true, false). % node_disco_info(Host, Node, From, true, false).
node_disco_features(Host, Node, From) -> %node_disco_features(Host, Node, From) ->
node_disco_info(Host, Node, From, false, true). % node_disco_info(Host, Node, From, false, true).
node_disco_info(Host, Node, From, Identity, Features) -> node_disco_info(Host, Node, From, Identity, Features) ->
Action = Action =
fun(#pubsub_node{type = Type, id = NodeId}) -> fun(#pubsub_node{type = Type, id = NodeId}) ->
@ -926,17 +962,16 @@ iq_disco_items(Host, Item, From, RSM) ->
{result, []}; {result, []};
[SNode] -> [SNode] ->
Node = string_to_node(SNode), Node = string_to_node(SNode),
Action = Action = fun(#pubsub_node{id = Idx, type = Type, options = Options}) ->
fun(#pubsub_node{type = Type, id = NodeId}) -> Owners = node_owners_call(Type, Idx),
%% TODO call get_items/6 instead for access control (EJAB-1033) {NodeItems, RsmOut} = case get_allowed_items_call(Host, Idx, From, Type, Options, Owners, RSM) of
{NodeItems, RsmOut} = case node_call(Type, get_items, [NodeId, From, RSM]) of {result, R} -> R;
{result, I} -> I; _ -> {[], none}
_ -> {[], none} end,
end,
Nodes = lists:map( Nodes = lists:map(
fun(#pubsub_node{nodeid = {_, SubNode}, options = Options}) -> fun(#pubsub_node{nodeid = {_, SubNode}, options = SubOptions}) ->
Attrs = Attrs =
case get_option(Options, title) of case get_option(SubOptions, title) of
false -> false ->
[{"jid", Host} |nodeAttr(SubNode)]; [{"jid", Host} |nodeAttr(SubNode)];
Title -> Title ->
@ -957,24 +992,6 @@ iq_disco_items(Host, Item, From, RSM) ->
end end
end. end.
iq_local(From, To, #iq{type = Type, sub_el = SubEl, xmlns = XMLNS, lang = Lang} = IQ) ->
ServerHost = To#jid.lserver,
%% Accept IQs to server only from our own users.
if
From#jid.lserver /= ServerHost ->
IQ#iq{type = error, sub_el = [?ERR_FORBIDDEN, SubEl]};
true ->
LOwner = jlib:jid_tolower(jlib:jid_remove_resource(From)),
Res = case XMLNS of
?NS_PUBSUB -> iq_pubsub(LOwner, ServerHost, From, Type, SubEl, Lang);
?NS_PUBSUB_OWNER -> iq_pubsub_owner(LOwner, ServerHost, From, Type, SubEl, Lang)
end,
case Res of
{result, IQRes} -> IQ#iq{type = result, sub_el = IQRes};
{error, Error} -> IQ#iq{type = error, sub_el = [Error, SubEl]}
end
end.
iq_sm(From, To, #iq{type = Type, sub_el = SubEl, xmlns = XMLNS, lang = Lang} = IQ) -> iq_sm(From, To, #iq{type = Type, sub_el = SubEl, xmlns = XMLNS, lang = Lang} = IQ) ->
ServerHost = To#jid.lserver, ServerHost = To#jid.lserver,
LOwner = jlib:jid_tolower(jlib:jid_remove_resource(To)), LOwner = jlib:jid_tolower(jlib:jid_remove_resource(To)),
@ -1687,25 +1704,8 @@ subscribe_node(Host, Node, From, JID, Configuration) ->
AccessModel = get_option(Options, access_model), AccessModel = get_option(Options, access_model),
SendLast = get_option(Options, send_last_published_item), SendLast = get_option(Options, send_last_published_item),
AllowedGroups = get_option(Options, roster_groups_allowed, []), AllowedGroups = get_option(Options, roster_groups_allowed, []),
{PresenceSubscription, RosterGroup} = Owners = node_owners_call(Type, NodeId),
case Host of {PresenceSubscription, RosterGroup} = get_presence_and_roster_permissions(Host, Subscriber, Owners, AccessModel, AllowedGroups),
{OUser, OServer, _} ->
get_roster_info(OUser, OServer,
Subscriber, AllowedGroups);
_ ->
case Subscriber of
{"", "", ""} ->
{false, false};
_ ->
case node_owners_call(Type, NodeId) of
[{OU, OS, _}|_] ->
get_roster_info(OU, OS,
Subscriber, AllowedGroups);
_ ->
{false, false}
end
end
end,
if if
not SubscribeFeature -> not SubscribeFeature ->
%% Node does not support subscriptions %% Node does not support subscriptions
@ -2054,14 +2054,8 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIDs, RSM) ->
PersistentFeature = lists:member("persistent-items", Features), PersistentFeature = lists:member("persistent-items", Features),
AccessModel = get_option(Options, access_model), AccessModel = get_option(Options, access_model),
AllowedGroups = get_option(Options, roster_groups_allowed, []), AllowedGroups = get_option(Options, roster_groups_allowed, []),
{PresenceSubscription, RosterGroup} = Owners = node_owners_call(Type, NodeId),
case Host of {PresenceSubscription, RosterGroup} = get_presence_and_roster_permissions(Host, From, Owners, AccessModel, AllowedGroups),
{OUser, OServer, _} ->
get_roster_info(OUser, OServer,
jlib:jid_tolower(From), AllowedGroups);
_ ->
{true, true}
end,
if if
not RetreiveFeature -> not RetreiveFeature ->
%% Item Retrieval Not Supported %% Item Retrieval Not Supported
@ -2112,6 +2106,17 @@ get_item(Host, Node, ItemId) ->
{result, {_, Items}} -> Items; {result, {_, Items}} -> Items;
Error -> Error Error -> Error
end. end.
get_allowed_items_call(Host, NodeIdx, From, Type, Options, Owners) ->
case get_allowed_items_call(Host, NodeIdx, From, Type, Options, Owners, none) of
{result, {I, _}} -> {result, I};
Error -> Error
end.
get_allowed_items_call(Host, NodeIdx, From, Type, Options, Owners, RSM) ->
AccessModel = get_option(Options, access_model),
AllowedGroups = get_option(Options, roster_groups_allowed, []),
{PresenceSubscription, RosterGroup} = get_presence_and_roster_permissions(Host, From, Owners, AccessModel, AllowedGroups),
node_call(Type, get_items, [NodeIdx, From, AccessModel, PresenceSubscription, RosterGroup, undefined, RSM]).
%% @spec (Host, Node, NodeId, Type, LJID, Number) -> any() %% @spec (Host, Node, NodeId, Type, LJID, Number) -> any()
%% Host = pubsubHost() %% Host = pubsubHost()
@ -2584,8 +2589,24 @@ set_subscriptions(Host, Node, From, EntitiesEls) ->
end end
end. end.
get_presence_and_roster_permissions(Host, From, Owners, AccessModel, AllowedGroups) ->
if (AccessModel == presence) or (AccessModel == roster) ->
case Host of
{User, Server, _} ->
get_roster_info(User, Server, From, AllowedGroups);
_ ->
[{OUser, OServer, _}|_] = Owners,
get_roster_info(OUser, OServer, From, AllowedGroups)
end;
true ->
{true, true}
end.
%% @spec (OwnerUser, OwnerServer, {SubscriberUser, SubscriberServer, SubscriberResource}, AllowedGroups) %% @spec (OwnerUser, OwnerServer, {SubscriberUser, SubscriberServer, SubscriberResource}, AllowedGroups)
%% -> {PresenceSubscription, RosterGroup} %% -> {PresenceSubscription, RosterGroup}
get_roster_info(_, _, {"", "", _}, _) ->
{false, false};
get_roster_info(OwnerUser, OwnerServer, {SubscriberUser, SubscriberServer, _}, AllowedGroups) -> get_roster_info(OwnerUser, OwnerServer, {SubscriberUser, SubscriberServer, _}, AllowedGroups) ->
{Subscription, Groups} = {Subscription, Groups} =
ejabberd_hooks:run_fold( ejabberd_hooks:run_fold(
@ -2597,7 +2618,9 @@ get_roster_info(OwnerUser, OwnerServer, {SubscriberUser, SubscriberServer, _}, A
RosterGroup = lists:any(fun(Group) -> RosterGroup = lists:any(fun(Group) ->
lists:member(Group, AllowedGroups) lists:member(Group, AllowedGroups)
end, Groups), end, Groups),
{PresenceSubscription, RosterGroup}. {PresenceSubscription, RosterGroup};
get_roster_info(OwnerUser, OwnerServer, JID, AllowedGroups) ->
get_roster_info(OwnerUser, OwnerServer, jlib:jid_tolower(JID), AllowedGroups).
%% @spec (AffiliationStr) -> Affiliation %% @spec (AffiliationStr) -> Affiliation
%% AffiliationStr = string() %% AffiliationStr = string()
@ -3582,6 +3605,10 @@ transaction(Host, Node, Action, Trans) ->
Error Error
end end
end, Trans). end, Trans).
transaction_on_nodes(Host, Action, Trans) ->
transaction(Host, fun() ->
{result, lists:foldl(Action, [], tree_call(Host, get_nodes, [Host]))}
end, Trans).
transaction(Host, Fun, Trans) -> transaction(Host, Fun, Trans) ->
transaction_retry(Host, Fun, Trans, 2). transaction_retry(Host, Fun, Trans, 2).

View File

@ -1,5 +1,5 @@
--- mod_pubsub.erl 2010-06-02 15:03:48.000000000 +0200 --- mod_pubsub.erl 2010-08-02 16:07:28.000000000 +0200
+++ mod_pubsub_odbc.erl 2010-06-02 16:45:38.000000000 +0200 +++ mod_pubsub_odbc.erl 2010-08-02 17:04:37.000000000 +0200
@@ -42,7 +42,7 @@ @@ -42,7 +42,7 @@
%%% 6.2.3.1, 6.2.3.5, and 6.3. For information on subscription leases see %%% 6.2.3.1, 6.2.3.5, and 6.3. For information on subscription leases see
%%% XEP-0060 section 12.18. %%% XEP-0060 section 12.18.
@ -22,7 +22,7 @@
%% exports for hooks %% exports for hooks
-export([presence_probe/3, -export([presence_probe/3,
@@ -104,7 +104,7 @@ @@ -103,7 +103,7 @@
string_to_affiliation/1, string_to_affiliation/1,
extended_error/2, extended_error/2,
extended_error/3, extended_error/3,
@ -31,7 +31,7 @@
]). ]).
%% API and gen_server callbacks %% API and gen_server callbacks
@@ -123,7 +123,7 @@ @@ -122,7 +122,7 @@
-export([send_loop/1 -export([send_loop/1
]). ]).
@ -40,7 +40,7 @@
-define(LOOPNAME, ejabberd_mod_pubsub_loop). -define(LOOPNAME, ejabberd_mod_pubsub_loop).
-define(PLUGIN_PREFIX, "node_"). -define(PLUGIN_PREFIX, "node_").
-define(TREE_PREFIX, "nodetree_"). -define(TREE_PREFIX, "nodetree_").
@@ -220,8 +220,6 @@ @@ -217,8 +217,6 @@
ok ok
end, end,
ejabberd_router:register_route(Host), ejabberd_router:register_route(Host),
@ -49,7 +49,7 @@
init_nodes(Host, ServerHost, NodeTree, Plugins), init_nodes(Host, ServerHost, NodeTree, Plugins),
State = #state{host = Host, State = #state{host = Host,
server_host = ServerHost, server_host = ServerHost,
@@ -280,207 +278,14 @@ @@ -277,207 +275,14 @@
init_nodes(Host, ServerHost, _NodeTree, Plugins) -> init_nodes(Host, ServerHost, _NodeTree, Plugins) ->
%% TODO, this call should be done plugin side %% TODO, this call should be done plugin side
@ -260,7 +260,7 @@
send_loop(State) -> send_loop(State) ->
receive receive
{presence, JID, Pid} -> {presence, JID, Pid} ->
@@ -491,17 +296,15 @@ @@ -488,17 +293,15 @@
%% for each node From is subscribed to %% for each node From is subscribed to
%% and if the node is so configured, send the last published item to From %% and if the node is so configured, send the last published item to From
lists:foreach(fun(PType) -> lists:foreach(fun(PType) ->
@ -284,7 +284,54 @@
true -> true ->
% resource not concerned about that subscription % resource not concerned about that subscription
ok ok
@@ -747,10 +550,10 @@ @@ -617,7 +420,8 @@
disco_identity(_Host, <<>>, _From) ->
[{xmlelement, "identity", [{"category", "pubsub"}, {"type", "pep"}], []}];
disco_identity(Host, Node, From) ->
- Action = fun(#pubsub_node{id = Idx, type = Type, options = Options, owners = Owners}) ->
+ Action = fun(#pubsub_node{id = Idx, type = Type, options = Options}) ->
+ Owners = node_owners_call(Type, Idx),
case get_allowed_items_call(Host, Idx, From, Type, Options, Owners) of
{result, _} ->
{result, [{xmlelement, "identity", [{"category", "pubsub"}, {"type", "pep"}], []},
@@ -652,7 +456,8 @@
[?NS_PUBSUB
| [?NS_PUBSUB++"#"++Feature || Feature <- features("pep")]];
disco_features(Host, Node, From) ->
- Action = fun(#pubsub_node{id = Idx, type = Type, options = Options, owners = Owners}) ->
+ Action = fun(#pubsub_node{id = Idx, type = Type, options = Options}) ->
+ Owners = node_owners_call(Type, Idx),
case get_allowed_items_call(Host, Idx, From, Type, Options, Owners) of
{result, _} ->
{result, [?NS_PUBSUB
@@ -677,7 +482,8 @@
Acc.
disco_items(Host, <<>>, From) ->
- Action = fun(#pubsub_node{nodeid ={_, NodeID}, options = Options, type = Type, id = Idx, owners = Owners}, Acc) ->
+ Action = fun(#pubsub_node{nodeid ={_, NodeID}, options = Options, type = Type, id = Idx}, Acc) ->
+ Owners = node_owners_call(Type, Idx),
case get_allowed_items_call(Host, Idx, From, Type, Options, Owners) of
{result, _} ->
[{xmlelement, "item",
@@ -695,13 +501,14 @@
_ -> Acc
end
end,
- case transaction(Host, Action, sync_dirty) of
+ case transaction_on_nodes(Host, Action, sync_dirty) of
{result, Items} -> Items;
_ -> []
end;
disco_items(Host, Node, From) ->
- Action = fun(#pubsub_node{id = Idx, type = Type, options = Options, owners = Owners}) ->
+ Action = fun(#pubsub_node{id = Idx, type = Type, options = Options}) ->
+ Owners = node_owners_call(Type, Idx),
case get_allowed_items_call(Host, Idx, From, Type, Options, Owners) of
{result, Items} ->
{result, [{xmlelement, "item",
@@ -781,10 +588,10 @@
lists:foreach(fun(PType) -> lists:foreach(fun(PType) ->
{result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Entity]), {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Entity]),
lists:foreach(fun lists:foreach(fun
@ -297,7 +344,7 @@
true -> true ->
node_action(Host, PType, unsubscribe_node, [NodeId, Entity, JID, all]); node_action(Host, PType, unsubscribe_node, [NodeId, Entity, JID, all]);
false -> false ->
@@ -920,7 +723,8 @@ @@ -952,7 +759,8 @@
sub_el = SubEl} = IQ -> sub_el = SubEl} = IQ ->
{xmlelement, _, QAttrs, _} = SubEl, {xmlelement, _, QAttrs, _} = SubEl,
Node = xml:get_attr_s("node", QAttrs), Node = xml:get_attr_s("node", QAttrs),
@ -307,7 +354,7 @@
{result, IQRes} -> {result, IQRes} ->
jlib:iq_to_xml( jlib:iq_to_xml(
IQ#iq{type = result, IQ#iq{type = result,
@@ -1033,7 +837,7 @@ @@ -1065,7 +873,7 @@
[] -> [] ->
["leaf"]; %% No sub-nodes: it's a leaf node ["leaf"]; %% No sub-nodes: it's a leaf node
_ -> _ ->
@ -316,7 +363,7 @@
{result, []} -> ["collection"]; {result, []} -> ["collection"];
{result, _} -> ["leaf", "collection"]; {result, _} -> ["leaf", "collection"];
_ -> [] _ -> []
@@ -1049,8 +853,9 @@ @@ -1081,8 +889,9 @@
[]; [];
true -> true ->
[{xmlelement, "feature", [{"var", ?NS_PUBSUB}], []} | [{xmlelement, "feature", [{"var", ?NS_PUBSUB}], []} |
@ -328,7 +375,7 @@
end, features(Type))] end, features(Type))]
end, end,
%% TODO: add meta-data info (spec section 5.4) %% TODO: add meta-data info (spec section 5.4)
@@ -1079,8 +884,9 @@ @@ -1111,8 +920,9 @@
{xmlelement, "feature", [{"var", ?NS_PUBSUB}], []}, {xmlelement, "feature", [{"var", ?NS_PUBSUB}], []},
{xmlelement, "feature", [{"var", ?NS_COMMANDS}], []}, {xmlelement, "feature", [{"var", ?NS_COMMANDS}], []},
{xmlelement, "feature", [{"var", ?NS_VCARD}], []}] ++ {xmlelement, "feature", [{"var", ?NS_VCARD}], []}] ++
@ -340,7 +387,7 @@
end, features(Host, Node))}; end, features(Host, Node))};
<<?NS_COMMANDS>> -> <<?NS_COMMANDS>> ->
command_disco_info(Host, Node, From); command_disco_info(Host, Node, From);
@@ -1090,7 +896,7 @@ @@ -1122,7 +932,7 @@
node_disco_info(Host, Node, From) node_disco_info(Host, Node, From)
end. end.
@ -349,7 +396,7 @@
case tree_action(Host, get_subnodes, [Host, <<>>, From]) of case tree_action(Host, get_subnodes, [Host, <<>>, From]) of
Nodes when is_list(Nodes) -> Nodes when is_list(Nodes) ->
{result, lists:map( {result, lists:map(
@@ -1107,14 +913,14 @@ @@ -1139,23 +949,24 @@
Other -> Other ->
Other Other
end; end;
@ -367,21 +414,20 @@
case string:tokens(Item, "!") of case string:tokens(Item, "!") of
[_SNode, _ItemID] -> [_SNode, _ItemID] ->
{result, []}; {result, []};
@@ -1122,10 +928,10 @@ [SNode] ->
Node = string_to_node(SNode), Node = string_to_node(SNode),
Action = - Action = fun(#pubsub_node{id = Idx, type = Type, options = Options, owners = Owners}) ->
fun(#pubsub_node{type = Type, id = NodeId}) -> - NodeItems = case get_allowed_items_call(Host, Idx, From, Type, Options, Owners) of
- % TODO call get_items/6 instead for access control (EJAB-1033) + Action = fun(#pubsub_node{id = Idx, type = Type, options = Options}) ->
- NodeItems = case node_call(Type, get_items, [NodeId, From]) of + Owners = node_owners_call(Type, Idx),
+ %% TODO call get_items/6 instead for access control (EJAB-1033) + {NodeItems, RsmOut} = case get_allowed_items_call(Host, Idx, From, Type, Options, Owners, RSM) of
+ {NodeItems, RsmOut} = case node_call(Type, get_items, [NodeId, From, RSM]) of {result, R} -> R;
{result, I} -> I; - _ -> []
- _ -> [] + _ -> {[], none}
+ _ -> {[], none} end,
end,
Nodes = lists:map( Nodes = lists:map(
fun(#pubsub_node{nodeid = {_, SubNode}, options = Options}) -> fun(#pubsub_node{nodeid = {_, SubNode}, options = SubOptions}) ->
@@ -1143,7 +949,7 @@ @@ -1173,7 +984,7 @@
{result, Name} = node_call(Type, get_item_name, [Host, Node, RN]), {result, Name} = node_call(Type, get_item_name, [Host, Node, RN]),
{xmlelement, "item", [{"jid", Host}, {"name", Name}], []} {xmlelement, "item", [{"jid", Host}, {"name", Name}], []}
end, NodeItems), end, NodeItems),
@ -390,7 +436,7 @@
end, end,
case transaction(Host, Node, Action, sync_dirty) of case transaction(Host, Node, Action, sync_dirty) of
{result, {_, Result}} -> {result, Result}; {result, {_, Result}} -> {result, Result};
@@ -1272,7 +1078,8 @@ @@ -1284,7 +1095,8 @@
(_, Acc) -> (_, Acc) ->
Acc Acc
end, [], xml:remove_cdata(Els)), end, [], xml:remove_cdata(Els)),
@ -400,7 +446,7 @@
{get, "subscriptions"} -> {get, "subscriptions"} ->
get_subscriptions(Host, Node, From, Plugins); get_subscriptions(Host, Node, From, Plugins);
{get, "affiliations"} -> {get, "affiliations"} ->
@@ -1295,7 +1102,9 @@ @@ -1307,7 +1119,9 @@
iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) -> iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) ->
{xmlelement, _, _, SubEls} = SubEl, {xmlelement, _, _, SubEls} = SubEl,
@ -411,7 +457,7 @@
case Action of case Action of
[{xmlelement, Name, Attrs, Els}] -> [{xmlelement, Name, Attrs, Els}] ->
Node = string_to_node(xml:get_attr_s("node", Attrs)), Node = string_to_node(xml:get_attr_s("node", Attrs)),
@@ -1425,7 +1234,8 @@ @@ -1437,7 +1251,8 @@
_ -> [] _ -> []
end end
end, end,
@ -421,7 +467,7 @@
sync_dirty) of sync_dirty) of
{result, Res} -> Res; {result, Res} -> Res;
Err -> Err Err -> Err
@@ -1464,7 +1274,7 @@ @@ -1476,7 +1291,7 @@
%%% authorization handling %%% authorization handling
@ -430,7 +476,7 @@
Lang = "en", %% TODO fix Lang = "en", %% TODO fix
Stanza = {xmlelement, "message", Stanza = {xmlelement, "message",
[], [],
@@ -1493,7 +1303,7 @@ @@ -1505,7 +1320,7 @@
[{xmlelement, "value", [], [{xmlcdata, "false"}]}]}]}]}, [{xmlelement, "value", [], [{xmlcdata, "false"}]}]}]}]},
lists:foreach(fun(Owner) -> lists:foreach(fun(Owner) ->
ejabberd_router:route(service_jid(Host), jlib:make_jid(Owner), Stanza) ejabberd_router:route(service_jid(Host), jlib:make_jid(Owner), Stanza)
@ -439,7 +485,7 @@
find_authorization_response(Packet) -> find_authorization_response(Packet) ->
{xmlelement, _Name, _Attrs, Els} = Packet, {xmlelement, _Name, _Attrs, Els} = Packet,
@@ -1557,8 +1367,8 @@ @@ -1569,8 +1384,8 @@
"true" -> true; "true" -> true;
_ -> false _ -> false
end, end,
@ -450,7 +496,7 @@
{result, Subscriptions} = node_call(Type, get_subscriptions, [NodeId, Subscriber]), {result, Subscriptions} = node_call(Type, get_subscriptions, [NodeId, Subscriber]),
if if
not IsApprover -> not IsApprover ->
@@ -1757,7 +1567,7 @@ @@ -1769,7 +1584,7 @@
Reply = [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}], Reply = [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}],
[{xmlelement, "create", nodeAttr(Node), [{xmlelement, "create", nodeAttr(Node),
[]}]}], []}]}],
@ -459,7 +505,7 @@
{result, {NodeId, SubsByDepth, {Result, broadcast}}} -> {result, {NodeId, SubsByDepth, {Result, broadcast}}} ->
broadcast_created_node(Host, Node, NodeId, Type, NodeOptions, SubsByDepth), broadcast_created_node(Host, Node, NodeId, Type, NodeOptions, SubsByDepth),
case Result of case Result of
@@ -1860,7 +1670,7 @@ @@ -1872,7 +1687,7 @@
%%<li>The node does not exist.</li> %%<li>The node does not exist.</li>
%%</ul> %%</ul>
subscribe_node(Host, Node, From, JID, Configuration) -> subscribe_node(Host, Node, From, JID, Configuration) ->
@ -468,33 +514,24 @@
{result, GoodSubOpts} -> GoodSubOpts; {result, GoodSubOpts} -> GoodSubOpts;
_ -> invalid _ -> invalid
end, end,
@@ -1868,7 +1678,7 @@ @@ -1880,7 +1695,7 @@
error -> {"", "", ""}; error -> {"", "", ""};
J -> jlib:jid_tolower(J) J -> jlib:jid_tolower(J)
end, end,
- Action = fun(#pubsub_node{options = Options, owners = [Owner|_], type = Type, id = NodeId}) -> - Action = fun(#pubsub_node{options = Options, owners = Owners, type = Type, id = NodeId}) ->
+ Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId}) -> + Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId}) ->
Features = features(Type), Features = features(Type),
SubscribeFeature = lists:member("subscribe", Features), SubscribeFeature = lists:member("subscribe", Features),
OptionsFeature = lists:member("subscription-options", Features), OptionsFeature = lists:member("subscription-options", Features),
@@ -1887,9 +1697,13 @@ @@ -1889,6 +1704,7 @@
{"", "", ""} -> AccessModel = get_option(Options, access_model),
{false, false}; SendLast = get_option(Options, send_last_published_item),
_ -> AllowedGroups = get_option(Options, roster_groups_allowed, []),
- {OU, OS, _} = Owner, + Owners = node_owners_call(Type, NodeId),
- get_roster_info(OU, OS, {PresenceSubscription, RosterGroup} = get_presence_and_roster_permissions(Host, Subscriber, Owners, AccessModel, AllowedGroups),
- Subscriber, AllowedGroups)
+ case node_owners_call(Type, NodeId) of
+ [{OU, OS, _}|_] ->
+ get_roster_info(OU, OS,
+ Subscriber, AllowedGroups);
+ _ ->
+ {false, false}
+ end
end
end,
if if
@@ -2220,7 +2034,7 @@ not SubscribeFeature ->
@@ -2218,7 +2034,7 @@
%% <p>The permission are not checked in this function.</p> %% <p>The permission are not checked in this function.</p>
%% @todo We probably need to check that the user doing the query has the right %% @todo We probably need to check that the user doing the query has the right
%% to read the items. %% to read the items.
@ -503,7 +540,22 @@
MaxItems = MaxItems =
if if
SMaxItems == "" -> get_max_items_node(Host); SMaxItems == "" -> get_max_items_node(Host);
@@ -2259,11 +2073,11 @@ @@ -2232,12 +2048,13 @@
{error, Error} ->
{error, Error};
_ ->
- Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId, owners = Owners}) ->
+ Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId}) ->
Features = features(Type),
RetreiveFeature = lists:member("retrieve-items", Features),
PersistentFeature = lists:member("persistent-items", Features),
AccessModel = get_option(Options, access_model),
AllowedGroups = get_option(Options, roster_groups_allowed, []),
+ Owners = node_owners_call(Type, NodeId),
{PresenceSubscription, RosterGroup} = get_presence_and_roster_permissions(Host, From, Owners, AccessModel, AllowedGroups),
if
not RetreiveFeature ->
@@ -2250,11 +2067,11 @@
node_call(Type, get_items, node_call(Type, get_items,
[NodeId, From, [NodeId, From,
AccessModel, PresenceSubscription, RosterGroup, AccessModel, PresenceSubscription, RosterGroup,
@ -517,7 +569,7 @@
SendItems = case ItemIDs of SendItems = case ItemIDs of
[] -> [] ->
Items; Items;
@@ -2276,7 +2090,8 @@ @@ -2267,7 +2084,8 @@
%% number of items sent to MaxItems: %% number of items sent to MaxItems:
{result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}], {result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}],
[{xmlelement, "items", nodeAttr(Node), [{xmlelement, "items", nodeAttr(Node),
@ -527,7 +579,24 @@
Error -> Error ->
Error Error
end end
@@ -2308,16 +2123,27 @@ @@ -2289,10 +2107,15 @@
Error -> Error
end.
get_allowed_items_call(Host, NodeIdx, From, Type, Options, Owners) ->
+ case get_allowed_items_call(Host, NodeIdx, From, Type, Options, Owners, none) of
+ {result, {I, _}} -> {result, I};
+ Error -> Error
+ end.
+get_allowed_items_call(Host, NodeIdx, From, Type, Options, Owners, RSM) ->
AccessModel = get_option(Options, access_model),
AllowedGroups = get_option(Options, roster_groups_allowed, []),
{PresenceSubscription, RosterGroup} = get_presence_and_roster_permissions(Host, From, Owners, AccessModel, AllowedGroups),
- node_call(Type, get_items, [NodeIdx, From, AccessModel, PresenceSubscription, RosterGroup, undefined]).
+ node_call(Type, get_items, [NodeIdx, From, AccessModel, PresenceSubscription, RosterGroup, undefined, RSM]).
%% @spec (Host, Node, NodeId, Type, LJID, Number) -> any()
@@ -2305,16 +2128,27 @@
%% @doc <p>Resend the items of a node to the user.</p> %% @doc <p>Resend the items of a node to the user.</p>
%% @todo use cache-last-item feature %% @todo use cache-last-item feature
send_items(Host, Node, NodeId, Type, LJID, last) -> send_items(Host, Node, NodeId, Type, LJID, last) ->
@ -561,7 +630,7 @@
send_items(Host, Node, NodeId, Type, LJID, Number) -> send_items(Host, Node, NodeId, Type, LJID, Number) ->
ToSend = case node_action(Host, Type, get_items, [NodeId, LJID]) of ToSend = case node_action(Host, Type, get_items, [NodeId, LJID]) of
{result, []} -> {result, []} ->
@@ -2443,7 +2269,8 @@ @@ -2440,7 +2274,8 @@
error -> error ->
{error, ?ERR_BAD_REQUEST}; {error, ?ERR_BAD_REQUEST};
_ -> _ ->
@ -571,7 +640,7 @@
case lists:member(Owner, Owners) of case lists:member(Owner, Owners) of
true -> true ->
OwnerJID = jlib:make_jid(Owner), OwnerJID = jlib:make_jid(Owner),
@@ -2453,24 +2280,7 @@ @@ -2450,24 +2285,7 @@
end, end,
lists:foreach( lists:foreach(
fun({JID, Affiliation}) -> fun({JID, Affiliation}) ->
@ -597,7 +666,7 @@
end, FilteredEntities), end, FilteredEntities),
{result, []}; {result, []};
_ -> _ ->
@@ -2523,11 +2333,11 @@ @@ -2520,11 +2338,11 @@
end. end.
read_sub(Subscriber, Node, NodeID, SubID, Lang) -> read_sub(Subscriber, Node, NodeID, SubID, Lang) ->
@ -611,7 +680,7 @@
OptionsEl = {xmlelement, "options", [{"jid", jlib:jid_to_string(Subscriber)}, OptionsEl = {xmlelement, "options", [{"jid", jlib:jid_to_string(Subscriber)},
{"subid", SubID}|nodeAttr(Node)], {"subid", SubID}|nodeAttr(Node)],
[XdataEl]}, [XdataEl]},
@@ -2553,7 +2363,7 @@ @@ -2550,7 +2368,7 @@
end. end.
set_options_helper(Configuration, JID, NodeID, SubID, Type) -> set_options_helper(Configuration, JID, NodeID, SubID, Type) ->
@ -620,7 +689,7 @@
{result, GoodSubOpts} -> GoodSubOpts; {result, GoodSubOpts} -> GoodSubOpts;
_ -> invalid _ -> invalid
end, end,
@@ -2582,7 +2392,7 @@ @@ -2579,7 +2397,7 @@
write_sub(_Subscriber, _NodeID, _SubID, invalid) -> write_sub(_Subscriber, _NodeID, _SubID, invalid) ->
{error, extended_error(?ERR_BAD_REQUEST, "invalid-options")}; {error, extended_error(?ERR_BAD_REQUEST, "invalid-options")};
write_sub(Subscriber, NodeID, SubID, Options) -> write_sub(Subscriber, NodeID, SubID, Options) ->
@ -629,7 +698,7 @@
{error, notfound} -> {error, notfound} ->
{error, extended_error(?ERR_NOT_ACCEPTABLE, "invalid-subid")}; {error, extended_error(?ERR_NOT_ACCEPTABLE, "invalid-subid")};
{result, _} -> {result, _} ->
@@ -2750,8 +2560,8 @@ @@ -2747,8 +2565,8 @@
{"subscription", subscription_to_string(Sub)} | nodeAttr(Node)], []}]}]}, {"subscription", subscription_to_string(Sub)} | nodeAttr(Node)], []}]}]},
ejabberd_router:route(service_jid(Host), jlib:make_jid(JID), Stanza) ejabberd_router:route(service_jid(Host), jlib:make_jid(JID), Stanza)
end, end,
@ -640,7 +709,7 @@
true -> true ->
Result = lists:foldl(fun({JID, Subscription, SubId}, Acc) -> Result = lists:foldl(fun({JID, Subscription, SubId}, Acc) ->
@@ -3088,7 +2898,7 @@ @@ -3103,7 +2921,7 @@
{Depth, [{N, get_node_subs(N)} || N <- Nodes]} {Depth, [{N, get_node_subs(N)} || N <- Nodes]}
end, tree_call(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)]))} end, tree_call(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)]))}
end, end,
@ -649,7 +718,7 @@
{result, CollSubs} -> CollSubs; {result, CollSubs} -> CollSubs;
_ -> [] _ -> []
end. end.
@@ -3102,9 +2912,9 @@ @@ -3117,9 +2935,9 @@
get_options_for_subs(NodeID, Subs) -> get_options_for_subs(NodeID, Subs) ->
lists:foldl(fun({JID, subscribed, SubID}, Acc) -> lists:foldl(fun({JID, subscribed, SubID}, Acc) ->
@ -661,7 +730,7 @@
_ -> Acc _ -> Acc
end; end;
(_, Acc) -> (_, Acc) ->
@@ -3308,6 +3118,30 @@ @@ -3323,6 +3141,30 @@
Result Result
end. end.
@ -692,7 +761,7 @@
%% @spec (Host, Options) -> MaxItems %% @spec (Host, Options) -> MaxItems
%% Host = host() %% Host = host()
%% Options = [Option] %% Options = [Option]
@@ -3704,7 +3538,13 @@ @@ -3719,7 +3561,13 @@
tree_action(Host, Function, Args) -> tree_action(Host, Function, Args) ->
?DEBUG("tree_action ~p ~p ~p",[Host,Function,Args]), ?DEBUG("tree_action ~p ~p ~p",[Host,Function,Args]),
Fun = fun() -> tree_call(Host, Function, Args) end, Fun = fun() -> tree_call(Host, Function, Args) end,
@ -707,7 +776,7 @@
%% @doc <p>node plugin call.</p> %% @doc <p>node plugin call.</p>
node_call(Type, Function, Args) -> node_call(Type, Function, Args) ->
@@ -3724,13 +3564,13 @@ @@ -3739,13 +3587,13 @@
node_action(Host, Type, Function, Args) -> node_action(Host, Type, Function, Args) ->
?DEBUG("node_action ~p ~p ~p ~p",[Host,Type,Function,Args]), ?DEBUG("node_action ~p ~p ~p ~p",[Host,Type,Function,Args]),
@ -723,9 +792,16 @@
case tree_call(Host, get_node, [Host, Node]) of case tree_call(Host, get_node, [Host, Node]) of
N when is_record(N, pubsub_node) -> N when is_record(N, pubsub_node) ->
case Action(N) of case Action(N) of
@@ -3743,8 +3583,14 @@ @@ -3757,13 +3605,19 @@
Error
end end
end, Trans). end, Trans).
-transaction(Host, Action, Trans) ->
- transaction(fun() ->
+transaction_on_nodes(Host, Action, Trans) ->
+ transaction(Host, fun() ->
{result, lists:foldl(Action, [], tree_call(Host, get_nodes, [Host]))}
end, Trans).
-transaction(Fun, Trans) -> -transaction(Fun, Trans) ->
- case catch mnesia:Trans(Fun) of - case catch mnesia:Trans(Fun) of
@ -740,7 +816,7 @@
{result, Result} -> {result, Result}; {result, Result} -> {result, Result};
{error, Error} -> {error, Error}; {error, Error} -> {error, Error};
{atomic, {result, Result}} -> {result, Result}; {atomic, {result, Result}} -> {result, Result};
@@ -3752,6 +3598,15 @@ @@ -3771,6 +3625,15 @@
{aborted, Reason} -> {aborted, Reason} ->
?ERROR_MSG("transaction return internal error: ~p~n", [{aborted, Reason}]), ?ERROR_MSG("transaction return internal error: ~p~n", [{aborted, Reason}]),
{error, ?ERR_INTERNAL_SERVER_ERROR}; {error, ?ERR_INTERNAL_SERVER_ERROR};
@ -756,7 +832,7 @@
{'EXIT', Reason} -> {'EXIT', Reason} ->
?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]), ?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]),
{error, ?ERR_INTERNAL_SERVER_ERROR}; {error, ?ERR_INTERNAL_SERVER_ERROR};
@@ -3760,6 +3615,17 @@ @@ -3779,6 +3642,17 @@
{error, ?ERR_INTERNAL_SERVER_ERROR} {error, ?ERR_INTERNAL_SERVER_ERROR}
end. end.

View File

@ -187,6 +187,18 @@ process_iq(From, To,
sub_el = [SubEl, ?ERR_BAD_REQUEST]} sub_el = [SubEl, ?ERR_BAD_REQUEST]}
end; end;
get -> get ->
{UsernameSubels, QuerySubels} =
case From of
#jid{user = User, lserver = Server} ->
case ejabberd_auth:is_user_exists(User,Server) of
true ->
{[{xmlcdata, User}], [{xmlelement, "registered", [], []}]};
false ->
{[{xmlcdata, User}], []}
end;
_ ->
{[], []}
end,
IQ#iq{type = result, IQ#iq{type = result,
sub_el = [{xmlelement, sub_el = [{xmlelement,
"query", "query",
@ -197,8 +209,9 @@ process_iq(From, To,
Lang, Lang,
"Choose a username and password " "Choose a username and password "
"to register with this server")}]}, "to register with this server")}]},
{xmlelement, "username", [], []}, {xmlelement, "username", [], UsernameSubels},
{xmlelement, "password", [], []}]}]} {xmlelement, "password", [], []}
| QuerySubels]}]}
end. end.
%% @doc Try to change password and return IQ response %% @doc Try to change password and return IQ response

View File

@ -33,8 +33,6 @@
-module(mod_http_bind). -module(mod_http_bind).
-author('steve@zeank.in-berlin.de'). -author('steve@zeank.in-berlin.de').
-define(MOD_HTTP_BIND_VERSION, "1.2").
%%-define(ejabberd_debug, true). %%-define(ejabberd_debug, true).
-behaviour(gen_mod). -behaviour(gen_mod).
@ -80,7 +78,7 @@ process(_Path, _Request) ->
[{xmlcdata, "400 Bad Request"}]}}. [{xmlcdata, "400 Bad Request"}]}}.
get_human_html_xmlel() -> get_human_html_xmlel() ->
Heading = "ejabberd " ++ atom_to_list(?MODULE) ++ " v" ++ ?MOD_HTTP_BIND_VERSION, Heading = "ejabberd " ++ atom_to_list(?MODULE),
{xmlelement, "html", [{"xmlns", "http://www.w3.org/1999/xhtml"}], {xmlelement, "html", [{"xmlns", "http://www.w3.org/1999/xhtml"}],
[{xmlelement, "head", [], [{xmlelement, "head", [],
[{xmlelement, "title", [], [{xmlcdata, Heading}]}]}, [{xmlelement, "title", [], [{xmlcdata, Heading}]}]},