mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-26 16:26:24 +01:00
Merge from trunk (r1752 to r1764).
Warning: Ejabberd may be broken until the merge is completly finished. PR: EJABP-1 SVN Revision: 1826
This commit is contained in:
parent
8a27b5446d
commit
bc51bd0dbd
56
ChangeLog
56
ChangeLog
@ -1,3 +1,7 @@
|
|||||||
|
2009-01-19 Jean-Sébastien Pédron <js.pedron@meetic-corp.com>
|
||||||
|
|
||||||
|
Merge from trunk (r1752 to r1764).
|
||||||
|
|
||||||
2009-01-19 Jean-Sébastien Pédron <js.pedron@meetic-corp.com>
|
2009-01-19 Jean-Sébastien Pédron <js.pedron@meetic-corp.com>
|
||||||
|
|
||||||
* src/ejabberd_auth_anonymous.erl: Fix accesses to the new #jid opaque
|
* src/ejabberd_auth_anonymous.erl: Fix accesses to the new #jid opaque
|
||||||
@ -160,6 +164,58 @@
|
|||||||
* src/mod_pubsub/mod_pubsub.erl: Added "access-whitelist" and
|
* src/mod_pubsub/mod_pubsub.erl: Added "access-whitelist" and
|
||||||
"member-affiliation" features (thanks to Andy Skelton)(EJAB-780)
|
"member-affiliation" features (thanks to Andy Skelton)(EJAB-780)
|
||||||
|
|
||||||
|
2008-12-29 Alexey Shchepin <alexey@process-one.net>
|
||||||
|
|
||||||
|
* src/ejabberd_c2s.erl: Bugfix in "from" attribute checking
|
||||||
|
|
||||||
|
2008-12-29 Evgeniy Khramtsov <ekhramtsov@process-one.net>
|
||||||
|
|
||||||
|
* src/odbc/ejabberd_odbc.erl: Print meaningful error message when
|
||||||
|
an SQL transaction exceeds number of restarts. Also rollbacks
|
||||||
|
this transaction to prevent deadlocks.
|
||||||
|
|
||||||
|
* src/odbc/odbc_queries.erl: replaced string:join/2 function.
|
||||||
|
Removed ugly "catch" statement from update_t/4.
|
||||||
|
WARNING: this change requires last version of mysql driver.
|
||||||
|
You can update it from ejabberd-modules repository.
|
||||||
|
|
||||||
|
2008-12-28 Mickael Remond <mremond@process-one.net>
|
||||||
|
|
||||||
|
* src/ejabberd_c2s.erl: We should allow use of bare resource in from by
|
||||||
|
the client (partially revert r1727) (EJAB-812).
|
||||||
|
|
||||||
|
2008-12-26 Badlop <badlop@process-one.net>
|
||||||
|
|
||||||
|
* src/web/ejabberd_web_admin.erl: Show in ejabberd Web Admin the
|
||||||
|
connection method and connected node of Jabber clients (thanks to
|
||||||
|
Oleg Palij)(EJAB-319)
|
||||||
|
|
||||||
|
* src/ejabberd_config.erl: Option outgoing_s2s_options to define
|
||||||
|
s2s outgoing behaviour: IPv4, IPv6 and timeout (thanks to Stephan
|
||||||
|
Maka)(EJAB-665)
|
||||||
|
* src/ejabberd_s2s_out.erl: Likewise
|
||||||
|
* src/ejabberd_socket.erl: Likewise
|
||||||
|
* src/ejabberd.cfg.example: Likewise
|
||||||
|
* doc/guide.tex: Likewise
|
||||||
|
* doc/guide.html: Likewise
|
||||||
|
|
||||||
|
2008-12-26 Evgeniy Khramtsov <ekhramtsov@process-one.net>
|
||||||
|
|
||||||
|
* src/odbc/ejabberd_odbc.erl: get rid of SERIALIZABLE isolation
|
||||||
|
level on MySQL connections.
|
||||||
|
* src/odbc/odbc_queries.erl: replaces all delete->insert chains
|
||||||
|
with update->insert.
|
||||||
|
* src/mod_privacy_odbc.erl: moved sql queries to odbc_queries.erl.
|
||||||
|
* src/mod_roster_odbc.erl: changed interface for odbc_queries.erl.
|
||||||
|
|
||||||
|
2008-12-24 Badlop <badlop@process-one.net>
|
||||||
|
|
||||||
|
* src/aclocal.m4: Fixes in configure script: fix
|
||||||
|
disable-ejabberd_zlib and disable-pam; in case of problems, PAM
|
||||||
|
verification aborts with error instead of warning. (EJAB-787)
|
||||||
|
* src/configure.ac: Likewise
|
||||||
|
* src/configure: Likewise
|
||||||
|
|
||||||
2008-12-23 Badlop <badlop@process-one.net>
|
2008-12-23 Badlop <badlop@process-one.net>
|
||||||
|
|
||||||
* src/acl.erl: New ACL: shared_group (thanks to Maxim Ryazanov)
|
* src/acl.erl: New ACL: shared_group (thanks to Maxim Ryazanov)
|
||||||
|
@ -745,6 +745,10 @@ use STARTTLS for s2s connections.
|
|||||||
file containing a SSL certificate.
|
file containing a SSL certificate.
|
||||||
</DD><DT CLASS="dt-description"><B><TT>{domain_certfile, Domain, Path}</TT></B></DT><DD CLASS="dd-description">
|
</DD><DT CLASS="dt-description"><B><TT>{domain_certfile, Domain, Path}</TT></B></DT><DD CLASS="dd-description">
|
||||||
Full path to the file containing the SSL certificate for a specific domain.
|
Full path to the file containing the SSL certificate for a specific domain.
|
||||||
|
</DD><DT CLASS="dt-description"><B><TT>{outgoing_s2s_options, Methods, Timeout}</TT></B></DT><DD CLASS="dd-description">
|
||||||
|
Specify which address families to try, in what order, and connect timeout in milliseconds.
|
||||||
|
By default it first tries connecting with IPv4, if that fails it tries using IPv6,
|
||||||
|
with a timeout of 10000 milliseconds.
|
||||||
</DD><DT CLASS="dt-description"><B><TT>{s2s_default_policy, allow|deny}</TT></B></DT><DD CLASS="dd-description">
|
</DD><DT CLASS="dt-description"><B><TT>{s2s_default_policy, allow|deny}</TT></B></DT><DD CLASS="dd-description">
|
||||||
The default policy for incoming and outgoing s2s connections to other Jabber servers.
|
The default policy for incoming and outgoing s2s connections to other Jabber servers.
|
||||||
The default value is <TT>allow</TT>.
|
The default value is <TT>allow</TT>.
|
||||||
@ -1032,6 +1036,10 @@ declarations of ACLs in the configuration file have the following syntax:
|
|||||||
</PRE></DD><DT CLASS="dt-description"><B><TT>{resource, <resource>}</TT></B></DT><DD CLASS="dd-description"> Matches any JID with a resource
|
</PRE></DD><DT CLASS="dt-description"><B><TT>{resource, <resource>}</TT></B></DT><DD CLASS="dd-description"> Matches any JID with a resource
|
||||||
<TT><resource></TT>. Example:
|
<TT><resource></TT>. Example:
|
||||||
<PRE CLASS="verbatim">{acl, mucklres, {resource, "muckl"}}.
|
<PRE CLASS="verbatim">{acl, mucklres, {resource, "muckl"}}.
|
||||||
|
</PRE></DD><DT CLASS="dt-description"><B><TT>{shared_group, <groupname>}</TT></B></DT><DD CLASS="dd-description"> Matches any member of a Shared Roster Group with name <TT><groupname></TT> in the virtual host. Example:
|
||||||
|
<PRE CLASS="verbatim">{acl, techgroupmembers, {shared_group, "techteam"}}.
|
||||||
|
</PRE></DD><DT CLASS="dt-description"><B><TT>{shared_group, <groupname>, <server>}</TT></B></DT><DD CLASS="dd-description"> Matches any member of a Shared Roster Group with name <TT><groupname></TT> in the virtual host <TT><server></TT>. Example:
|
||||||
|
<PRE CLASS="verbatim">{acl, techgroupmembers, {shared_group, "techteam", "example.org"}}.
|
||||||
</PRE></DD><DT CLASS="dt-description"><B><TT>{user_regexp, <regexp>}</TT></B></DT><DD CLASS="dd-description"> Matches any local user with a name that
|
</PRE></DD><DT CLASS="dt-description"><B><TT>{user_regexp, <regexp>}</TT></B></DT><DD CLASS="dd-description"> Matches any local user with a name that
|
||||||
matches <TT><regexp></TT> on local virtual hosts. Example:
|
matches <TT><regexp></TT> on local virtual hosts. Example:
|
||||||
<PRE CLASS="verbatim">{acl, tests, {user_regexp, "^test[0-9]*$"}}.
|
<PRE CLASS="verbatim">{acl, tests, {user_regexp, "^test[0-9]*$"}}.
|
||||||
|
@ -870,6 +870,10 @@ There are some additional global options:
|
|||||||
file containing a SSL certificate.
|
file containing a SSL certificate.
|
||||||
\titem{\{domain\_certfile, Domain, Path\}} \ind{options!domain\_certfile}
|
\titem{\{domain\_certfile, Domain, Path\}} \ind{options!domain\_certfile}
|
||||||
Full path to the file containing the SSL certificate for a specific domain.
|
Full path to the file containing the SSL certificate for a specific domain.
|
||||||
|
\titem{\{outgoing\_s2s\_options, Methods, Timeout\}} \ind{options!outgoing\_s2s\_options}
|
||||||
|
Specify which address families to try, in what order, and connect timeout in milliseconds.
|
||||||
|
By default it first tries connecting with IPv4, if that fails it tries using IPv6,
|
||||||
|
with a timeout of 10000 milliseconds.
|
||||||
\titem{\{s2s\_default\_policy, allow|deny\}}
|
\titem{\{s2s\_default\_policy, allow|deny\}}
|
||||||
The default policy for incoming and outgoing s2s connections to other Jabber servers.
|
The default policy for incoming and outgoing s2s connections to other Jabber servers.
|
||||||
The default value is \term{allow}.
|
The default value is \term{allow}.
|
||||||
|
17
src/aclocal.m4
vendored
17
src/aclocal.m4
vendored
@ -15,7 +15,7 @@ AC_DEFUN(AM_WITH_EXPAT,
|
|||||||
[ expat_found=no ],
|
[ expat_found=no ],
|
||||||
"$EXPAT_LIBS")
|
"$EXPAT_LIBS")
|
||||||
if test $expat_found = no; then
|
if test $expat_found = no; then
|
||||||
AC_MSG_ERROR([Could not find the Expat library])
|
AC_MSG_ERROR([Could not find development files of Expat library])
|
||||||
fi
|
fi
|
||||||
expat_save_CFLAGS="$CFLAGS"
|
expat_save_CFLAGS="$CFLAGS"
|
||||||
CFLAGS="$CFLAGS $EXPAT_CFLAGS"
|
CFLAGS="$CFLAGS $EXPAT_CFLAGS"
|
||||||
@ -36,6 +36,7 @@ AC_DEFUN(AM_WITH_ZLIB,
|
|||||||
[ AC_ARG_WITH(zlib,
|
[ AC_ARG_WITH(zlib,
|
||||||
[AC_HELP_STRING([--with-zlib=PREFIX], [prefix where zlib is installed])])
|
[AC_HELP_STRING([--with-zlib=PREFIX], [prefix where zlib is installed])])
|
||||||
|
|
||||||
|
if test x"$ejabberd_zlib" != x; then
|
||||||
ZLIB_CFLAGS=
|
ZLIB_CFLAGS=
|
||||||
ZLIB_LIBS=
|
ZLIB_LIBS=
|
||||||
if test x"$with_zlib" != x; then
|
if test x"$with_zlib" != x; then
|
||||||
@ -49,7 +50,7 @@ AC_DEFUN(AM_WITH_ZLIB,
|
|||||||
[ zlib_found=no ],
|
[ zlib_found=no ],
|
||||||
"$ZLIB_LIBS")
|
"$ZLIB_LIBS")
|
||||||
if test $zlib_found = no; then
|
if test $zlib_found = no; then
|
||||||
AC_MSG_ERROR([Could not find the zlib library])
|
AC_MSG_ERROR([Could not find development files of zlib library. Install them or disable `ejabberd_zlib' with: --disable-ejabberd_zlib])
|
||||||
fi
|
fi
|
||||||
zlib_save_CFLAGS="$CFLAGS"
|
zlib_save_CFLAGS="$CFLAGS"
|
||||||
CFLAGS="$CFLAGS $ZLIB_CFLAGS"
|
CFLAGS="$CFLAGS $ZLIB_CFLAGS"
|
||||||
@ -57,19 +58,20 @@ AC_DEFUN(AM_WITH_ZLIB,
|
|||||||
CPPFLAGS="$CPPFLAGS $ZLIB_CFLAGS"
|
CPPFLAGS="$CPPFLAGS $ZLIB_CFLAGS"
|
||||||
AC_CHECK_HEADERS(zlib.h, , zlib_found=no)
|
AC_CHECK_HEADERS(zlib.h, , zlib_found=no)
|
||||||
if test $zlib_found = no; then
|
if test $zlib_found = no; then
|
||||||
AC_MSG_ERROR([Could not find zlib.h])
|
AC_MSG_ERROR([Could not find zlib.h. Install it or disable `ejabberd_zlib' with: --disable-ejabberd_zlib])
|
||||||
fi
|
fi
|
||||||
CFLAGS="$zlib_save_CFLAGS"
|
CFLAGS="$zlib_save_CFLAGS"
|
||||||
CPPFLAGS="$zlib_save_CPPFLAGS"
|
CPPFLAGS="$zlib_save_CPPFLAGS"
|
||||||
|
|
||||||
AC_SUBST(ZLIB_CFLAGS)
|
AC_SUBST(ZLIB_CFLAGS)
|
||||||
AC_SUBST(ZLIB_LIBS)
|
AC_SUBST(ZLIB_LIBS)
|
||||||
|
fi
|
||||||
])
|
])
|
||||||
|
|
||||||
AC_DEFUN(AM_WITH_PAM,
|
AC_DEFUN(AM_WITH_PAM,
|
||||||
[ AC_ARG_WITH(pam,
|
[ AC_ARG_WITH(pam,
|
||||||
[AC_HELP_STRING([--with-pam=PREFIX], [prefix where PAM is installed])])
|
[AC_HELP_STRING([--with-pam=PREFIX], [prefix where PAM is installed])])
|
||||||
|
if test x"$pam" != x; then
|
||||||
PAM_CFLAGS=
|
PAM_CFLAGS=
|
||||||
PAM_LIBS=
|
PAM_LIBS=
|
||||||
if test x"$with_pam" != x; then
|
if test x"$with_pam" != x; then
|
||||||
@ -83,7 +85,7 @@ AC_DEFUN(AM_WITH_PAM,
|
|||||||
[ pam_found=no ],
|
[ pam_found=no ],
|
||||||
"$PAM_LIBS")
|
"$PAM_LIBS")
|
||||||
if test $pam_found = no; then
|
if test $pam_found = no; then
|
||||||
AC_MSG_WARN([Could not find the PAM library])
|
AC_MSG_ERROR([Could not find development files of PAM library. Install them or disable `pam' with: --disable-pam])
|
||||||
fi
|
fi
|
||||||
pam_save_CFLAGS="$CFLAGS"
|
pam_save_CFLAGS="$CFLAGS"
|
||||||
CFLAGS="$CFLAGS $PAM_CFLAGS"
|
CFLAGS="$CFLAGS $PAM_CFLAGS"
|
||||||
@ -91,13 +93,14 @@ AC_DEFUN(AM_WITH_PAM,
|
|||||||
CPPFLAGS="$CPPFLAGS $PAM_CFLAGS"
|
CPPFLAGS="$CPPFLAGS $PAM_CFLAGS"
|
||||||
AC_CHECK_HEADERS(security/pam_appl.h, , pam_found=no)
|
AC_CHECK_HEADERS(security/pam_appl.h, , pam_found=no)
|
||||||
if test $pam_found = no; then
|
if test $pam_found = no; then
|
||||||
AC_MSG_WARN([Could not find security/pam_appl.h])
|
AC_MSG_ERROR([Could not find security/pam_appl.h. Install it or disable `pam' with: --disable-pam])
|
||||||
fi
|
fi
|
||||||
CFLAGS="$pam_save_CFLAGS"
|
CFLAGS="$pam_save_CFLAGS"
|
||||||
CPPFLAGS="$pam_save_CPPFLAGS"
|
CPPFLAGS="$pam_save_CPPFLAGS"
|
||||||
|
|
||||||
AC_SUBST(PAM_CFLAGS)
|
AC_SUBST(PAM_CFLAGS)
|
||||||
AC_SUBST(PAM_LIBS)
|
AC_SUBST(PAM_LIBS)
|
||||||
|
fi
|
||||||
])
|
])
|
||||||
|
|
||||||
AC_DEFUN(AM_WITH_ERLANG,
|
AC_DEFUN(AM_WITH_ERLANG,
|
||||||
@ -346,7 +349,7 @@ if test x"$tls" != x; then
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
if test x${have_openssl} != xyes; then
|
if test x${have_openssl} != xyes; then
|
||||||
AC_MSG_ERROR([openssl library cannot be found. Install openssl or disable `tls' module (--disable-tls).])
|
AC_MSG_ERROR([Could not find development files of OpenSSL library. Install them or disable `tls' with: --disable-tls])
|
||||||
fi
|
fi
|
||||||
AC_SUBST(SSL_LIBS)
|
AC_SUBST(SSL_LIBS)
|
||||||
AC_SUBST(SSL_CFLAGS)
|
AC_SUBST(SSL_CFLAGS)
|
||||||
|
1243
src/configure
vendored
1243
src/configure
vendored
File diff suppressed because it is too large
Load Diff
@ -18,10 +18,6 @@ AM_WITH_ERLANG
|
|||||||
AM_ICONV
|
AM_ICONV
|
||||||
#locating libexpat
|
#locating libexpat
|
||||||
AM_WITH_EXPAT
|
AM_WITH_EXPAT
|
||||||
#locating zlib
|
|
||||||
AM_WITH_ZLIB
|
|
||||||
#locating PAM
|
|
||||||
AM_WITH_PAM
|
|
||||||
|
|
||||||
# Checks for typedefs, structures, and compiler characteristics.
|
# Checks for typedefs, structures, and compiler characteristics.
|
||||||
AC_C_CONST
|
AC_C_CONST
|
||||||
@ -36,16 +32,22 @@ AC_PREFIX_DEFAULT(/)
|
|||||||
AC_FUNC_MALLOC
|
AC_FUNC_MALLOC
|
||||||
AC_HEADER_STDC
|
AC_HEADER_STDC
|
||||||
|
|
||||||
AC_MOD_ENABLE(mod_pubsub, yes)
|
|
||||||
AC_MOD_ENABLE(mod_irc, yes)
|
AC_MOD_ENABLE(mod_irc, yes)
|
||||||
AC_MOD_ENABLE(mod_muc, yes)
|
AC_MOD_ENABLE(mod_muc, yes)
|
||||||
AC_MOD_ENABLE(mod_proxy65, yes)
|
AC_MOD_ENABLE(mod_proxy65, yes)
|
||||||
|
AC_MOD_ENABLE(mod_pubsub, yes)
|
||||||
AC_MOD_ENABLE(eldap, yes)
|
AC_MOD_ENABLE(eldap, yes)
|
||||||
AC_MOD_ENABLE(pam, no)
|
|
||||||
AC_MOD_ENABLE(web, yes)
|
|
||||||
AC_MOD_ENABLE(tls, yes)
|
|
||||||
AC_MOD_ENABLE(odbc, no)
|
AC_MOD_ENABLE(odbc, no)
|
||||||
|
AC_MOD_ENABLE(tls, yes)
|
||||||
|
AC_MOD_ENABLE(web, yes)
|
||||||
|
|
||||||
AC_MOD_ENABLE(ejabberd_zlib, yes)
|
AC_MOD_ENABLE(ejabberd_zlib, yes)
|
||||||
|
#locating zlib
|
||||||
|
AM_WITH_ZLIB
|
||||||
|
|
||||||
|
AC_MOD_ENABLE(pam, no)
|
||||||
|
#locating PAM
|
||||||
|
AM_WITH_PAM
|
||||||
|
|
||||||
AC_ARG_ENABLE(hipe,
|
AC_ARG_ENABLE(hipe,
|
||||||
[AC_HELP_STRING([--enable-hipe], [compile natively with HiPE, not recommended (default: no)])],
|
[AC_HELP_STRING([--enable-hipe], [compile natively with HiPE, not recommended (default: no)])],
|
||||||
|
@ -186,6 +186,13 @@
|
|||||||
%%{{s2s_host, "goodhost.org"}, allow}.
|
%%{{s2s_host, "goodhost.org"}, allow}.
|
||||||
%%{{s2s_host, "badhost.org"}, deny}.
|
%%{{s2s_host, "badhost.org"}, deny}.
|
||||||
|
|
||||||
|
%%
|
||||||
|
%% Outgoing S2S options
|
||||||
|
%%
|
||||||
|
%% Preferred address families (which to try first) and connect timeout
|
||||||
|
%% in milliseconds.
|
||||||
|
%%
|
||||||
|
%%{outgoing_s2s_options, [ipv4, ipv6], 10000}.
|
||||||
|
|
||||||
%%% ==============
|
%%% ==============
|
||||||
%%% AUTHENTICATION
|
%%% AUTHENTICATION
|
||||||
|
@ -1890,14 +1890,26 @@ check_from(El, FromJID) ->
|
|||||||
case exmpp_stanza:get_sender(El) of
|
case exmpp_stanza:get_sender(El) of
|
||||||
undefined ->
|
undefined ->
|
||||||
El;
|
El;
|
||||||
SJID ->
|
{value, SJID} ->
|
||||||
try
|
try
|
||||||
JID = exmpp_jid:binary_to_jid(SJID),
|
JIDEl = exmpp_jid:parse_jid(SJID),
|
||||||
case exmpp_jid:compare_jids(JID, FromJID) of
|
case exmpp_jid:lresource(JIDEl) of
|
||||||
true ->
|
undefined ->
|
||||||
El;
|
%% Matching JID: The stanza is ok
|
||||||
false ->
|
case exmpp_jid:compare_bare_jids(JIDEl, FromJID) of
|
||||||
'invalid-from'
|
true ->
|
||||||
|
El;
|
||||||
|
false ->
|
||||||
|
'invalid-from'
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
%% Matching JID: The stanza is ok
|
||||||
|
case exmpp_jid:compare_jids(JIDEl, FromJID) of
|
||||||
|
true ->
|
||||||
|
El;
|
||||||
|
false ->
|
||||||
|
'invalid-from'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
catch
|
catch
|
||||||
_:_ ->
|
_:_ ->
|
||||||
|
@ -331,6 +331,8 @@ process_term(Term, State) ->
|
|||||||
add_option(language, Val, State);
|
add_option(language, Val, State);
|
||||||
{outgoing_s2s_port, Port} ->
|
{outgoing_s2s_port, Port} ->
|
||||||
add_option(outgoing_s2s_port, Port, State);
|
add_option(outgoing_s2s_port, Port, State);
|
||||||
|
{outgoing_s2s_options, Methods, Timeout} ->
|
||||||
|
add_option(outgoing_s2s_options, {Methods, Timeout}, State);
|
||||||
{s2s_use_starttls, Port} ->
|
{s2s_use_starttls, Port} ->
|
||||||
add_option(s2s_use_starttls, Port, State);
|
add_option(s2s_use_starttls, Port, State);
|
||||||
{s2s_certfile, CertFile} ->
|
{s2s_certfile, CertFile} ->
|
||||||
|
@ -108,6 +108,8 @@
|
|||||||
]).
|
]).
|
||||||
|
|
||||||
|
|
||||||
|
-define(SOCKET_DEFAULT_RESULT, {error, badarg}).
|
||||||
|
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
%%% API
|
%%% API
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
@ -195,7 +197,7 @@ open_socket(init, StateData) ->
|
|||||||
_ ->
|
_ ->
|
||||||
open_socket1(Addr, Port)
|
open_socket1(Addr, Port)
|
||||||
end
|
end
|
||||||
end, {error, badarg}, AddrList) of
|
end, ?SOCKET_DEFAULT_RESULT, AddrList) of
|
||||||
{ok, Socket} ->
|
{ok, Socket} ->
|
||||||
Version = if
|
Version = if
|
||||||
StateData#state.use_v10 ->
|
StateData#state.use_v10 ->
|
||||||
@ -231,34 +233,40 @@ open_socket(_, StateData) ->
|
|||||||
{next_state, open_socket, StateData}.
|
{next_state, open_socket, StateData}.
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
%%----------------------------------------------------------------------
|
||||||
open_socket1(Addr, Port) ->
|
%% IPv4
|
||||||
?DEBUG("s2s_out: connecting to ~s:~p~n", [Addr, Port]),
|
open_socket1({_,_,_,_} = Addr, Port) ->
|
||||||
Res = case catch ejabberd_socket:connect(
|
open_socket2(inet, Addr, Port);
|
||||||
Addr, Port,
|
|
||||||
[binary, {packet, 0},
|
%% IPv6
|
||||||
{active, false}]) of
|
open_socket1({_,_,_,_,_,_,_,_} = Addr, Port) ->
|
||||||
{ok, _Socket} = R -> R;
|
open_socket2(inet6, Addr, Port);
|
||||||
{error, Reason1} ->
|
|
||||||
?DEBUG("s2s_out: connect return ~p~n", [Reason1]),
|
%% Hostname
|
||||||
catch ejabberd_socket:connect(
|
open_socket1(Host, Port) ->
|
||||||
Addr, Port,
|
lists:foldl(fun(_Family, {ok, _Socket} = R) ->
|
||||||
[binary, {packet, 0},
|
R;
|
||||||
{active, false}, inet6]);
|
(Family, _) ->
|
||||||
{'EXIT', Reason1} ->
|
Addrs = get_addrs(Host, Family),
|
||||||
?DEBUG("s2s_out: connect crashed ~p~n", [Reason1]),
|
lists:foldl(fun(_Addr, {ok, _Socket} = R) ->
|
||||||
catch ejabberd_socket:connect(
|
R;
|
||||||
Addr, Port,
|
(Addr, _) ->
|
||||||
[binary, {packet, 0},
|
open_socket1(Addr, Port)
|
||||||
{active, false}, inet6])
|
end, ?SOCKET_DEFAULT_RESULT, Addrs)
|
||||||
end,
|
end, ?SOCKET_DEFAULT_RESULT, outgoing_s2s_families()).
|
||||||
case Res of
|
|
||||||
{ok, Socket} ->
|
open_socket2(Type, Addr, Port) ->
|
||||||
{ok, Socket};
|
?DEBUG("s2s_out: connecting to ~p:~p~n", [Addr, Port]),
|
||||||
{error, Reason} ->
|
Timeout = outgoing_s2s_timeout(),
|
||||||
?DEBUG("s2s_out: inet6 connect return ~p~n", [Reason]),
|
case (catch ejabberd_socket:connect(Addr, Port,
|
||||||
{error, Reason};
|
[binary, {packet, 0},
|
||||||
|
{active, false}, Type],
|
||||||
|
Timeout)) of
|
||||||
|
{ok, _Socket} = R -> R;
|
||||||
|
{error, Reason} = R ->
|
||||||
|
?DEBUG("s2s_out: connect return ~p~n", [Reason]),
|
||||||
|
R;
|
||||||
{'EXIT', Reason} ->
|
{'EXIT', Reason} ->
|
||||||
?DEBUG("s2s_out: inet6 connect crashed ~p~n", [Reason]),
|
?DEBUG("s2s_out: connect crashed ~p~n", [Reason]),
|
||||||
{error, Reason}
|
{error, Reason}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
@ -953,6 +961,23 @@ test_get_addr_port(Server) ->
|
|||||||
end
|
end
|
||||||
end, [], lists:seq(1, 100000)).
|
end, [], lists:seq(1, 100000)).
|
||||||
|
|
||||||
|
get_addrs(Host, Family) ->
|
||||||
|
Type = case Family of
|
||||||
|
inet4 -> inet;
|
||||||
|
ipv4 -> inet;
|
||||||
|
inet6 -> inet6;
|
||||||
|
ipv6 -> inet6
|
||||||
|
end,
|
||||||
|
case inet:gethostbyname(Host, Type) of
|
||||||
|
{ok, #hostent{h_addr_list = Addrs}} ->
|
||||||
|
?DEBUG("~s of ~s resolved to: ~p~n", [Type, Host, Addrs]),
|
||||||
|
Addrs;
|
||||||
|
{error, Reason} ->
|
||||||
|
?DEBUG("~s lookup of '~s' failed: ~p~n", [Type, Host, Reason]),
|
||||||
|
[]
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
outgoing_s2s_port() ->
|
outgoing_s2s_port() ->
|
||||||
case ejabberd_config:get_local_option(outgoing_s2s_port) of
|
case ejabberd_config:get_local_option(outgoing_s2s_port) of
|
||||||
Port when is_integer(Port) ->
|
Port when is_integer(Port) ->
|
||||||
@ -961,6 +986,36 @@ outgoing_s2s_port() ->
|
|||||||
5269
|
5269
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
outgoing_s2s_families() ->
|
||||||
|
case ejabberd_config:get_local_option(outgoing_s2s_options) of
|
||||||
|
{Families, _} when is_list(Families) ->
|
||||||
|
Families;
|
||||||
|
undefined ->
|
||||||
|
%% DISCUSSION: Why prefer IPv4 first?
|
||||||
|
%%
|
||||||
|
%% IPv4 connectivity will be available for everyone for
|
||||||
|
%% many years to come. So, there's absolutely no benefit
|
||||||
|
%% in preferring IPv6 connections which are flaky at best
|
||||||
|
%% nowadays.
|
||||||
|
%%
|
||||||
|
%% On the other hand content providers hesitate putting up
|
||||||
|
%% AAAA records for their sites due to the mentioned
|
||||||
|
%% quality of current IPv6 connectivity. Making IPv6 the a
|
||||||
|
%% `fallback' may avoid these problems elegantly.
|
||||||
|
[ipv4, ipv6]
|
||||||
|
end.
|
||||||
|
|
||||||
|
outgoing_s2s_timeout() ->
|
||||||
|
case ejabberd_config:get_local_option(outgoing_s2s_options) of
|
||||||
|
{_, Timeout} when is_integer(Timeout) ->
|
||||||
|
Timeout;
|
||||||
|
{_, infinity} ->
|
||||||
|
infinity;
|
||||||
|
undefined ->
|
||||||
|
%% 10 seconds
|
||||||
|
10000
|
||||||
|
end.
|
||||||
|
|
||||||
%% 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;
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
%% API
|
%% API
|
||||||
-export([start/4,
|
-export([start/4,
|
||||||
connect/3,
|
connect/3,
|
||||||
|
connect/4,
|
||||||
starttls/2,
|
starttls/2,
|
||||||
starttls/3,
|
starttls/3,
|
||||||
compress/1,
|
compress/1,
|
||||||
@ -94,7 +95,10 @@ start(Module, SockMod, Socket, Opts) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
connect(Addr, Port, Opts) ->
|
connect(Addr, Port, Opts) ->
|
||||||
case gen_tcp:connect(Addr, Port, Opts) of
|
connect(Addr, Port, Opts, infinity).
|
||||||
|
|
||||||
|
connect(Addr, Port, Opts, Timeout) ->
|
||||||
|
case gen_tcp:connect(Addr, Port, Opts, Timeout) of
|
||||||
{ok, Socket} ->
|
{ok, Socket} ->
|
||||||
Receiver = ejabberd_receiver:start(Socket, gen_tcp, none),
|
Receiver = ejabberd_receiver:start(Socket, gen_tcp, none),
|
||||||
SocketData = #socket_state{sockmod = gen_tcp,
|
SocketData = #socket_state{sockmod = gen_tcp,
|
||||||
|
@ -775,132 +775,66 @@ item_to_raw(#listitem{type = Type,
|
|||||||
SMatchMessage = if MatchMessage -> "1"; true -> "0" end,
|
SMatchMessage = if MatchMessage -> "1"; true -> "0" end,
|
||||||
SMatchPresenceIn = if MatchPresenceIn -> "1"; true -> "0" end,
|
SMatchPresenceIn = if MatchPresenceIn -> "1"; true -> "0" end,
|
||||||
SMatchPresenceOut = if MatchPresenceOut -> "1"; true -> "0" end,
|
SMatchPresenceOut = if MatchPresenceOut -> "1"; true -> "0" end,
|
||||||
["'", SType, "', "
|
[SType, SValue, SAction, SOrder, SMatchAll, SMatchIQ,
|
||||||
"'", SValue, "', "
|
SMatchMessage, SMatchPresenceIn, SMatchPresenceOut].
|
||||||
"'", SAction, "', "
|
|
||||||
"'", SOrder, "', "
|
|
||||||
"'", SMatchAll, "', "
|
|
||||||
"'", SMatchIQ, "', "
|
|
||||||
"'", SMatchMessage, "', "
|
|
||||||
"'", SMatchPresenceIn, "', "
|
|
||||||
"'", SMatchPresenceOut, "'"].
|
|
||||||
|
|
||||||
|
|
||||||
sql_get_default_privacy_list(LUser, LServer) ->
|
sql_get_default_privacy_list(LUser, LServer) ->
|
||||||
Username = ejabberd_odbc:escape(LUser),
|
Username = ejabberd_odbc:escape(LUser),
|
||||||
ejabberd_odbc:sql_query(
|
odbc_queries:get_default_privacy_list(LServer, Username).
|
||||||
LServer,
|
|
||||||
["select name from privacy_default_list "
|
|
||||||
"where username='", Username, "';"]).
|
|
||||||
|
|
||||||
sql_get_default_privacy_list_t(LUser) ->
|
sql_get_default_privacy_list_t(LUser) ->
|
||||||
Username = ejabberd_odbc:escape(LUser),
|
Username = ejabberd_odbc:escape(LUser),
|
||||||
ejabberd_odbc:sql_query_t(
|
odbc_queries:get_default_privacy_list_t(Username).
|
||||||
["select name from privacy_default_list "
|
|
||||||
"where username='", Username, "';"]).
|
|
||||||
|
|
||||||
sql_get_privacy_list_names(LUser, LServer) ->
|
sql_get_privacy_list_names(LUser, LServer) ->
|
||||||
Username = ejabberd_odbc:escape(LUser),
|
Username = ejabberd_odbc:escape(LUser),
|
||||||
ejabberd_odbc:sql_query(
|
odbc_queries:get_privacy_list_names(LServer, Username).
|
||||||
LServer,
|
|
||||||
["select name from privacy_list "
|
|
||||||
"where username='", Username, "';"]).
|
|
||||||
|
|
||||||
sql_get_privacy_list_names_t(LUser) ->
|
sql_get_privacy_list_names_t(LUser) ->
|
||||||
Username = ejabberd_odbc:escape(LUser),
|
Username = ejabberd_odbc:escape(LUser),
|
||||||
ejabberd_odbc:sql_query_t(
|
odbc_queries:get_privacy_list_names_t(Username).
|
||||||
["select name from privacy_list "
|
|
||||||
"where username='", Username, "';"]).
|
|
||||||
|
|
||||||
sql_get_privacy_list_id(LUser, LServer, Name) ->
|
sql_get_privacy_list_id(LUser, LServer, Name) ->
|
||||||
Username = ejabberd_odbc:escape(LUser),
|
Username = ejabberd_odbc:escape(LUser),
|
||||||
SName = ejabberd_odbc:escape(Name),
|
SName = ejabberd_odbc:escape(Name),
|
||||||
ejabberd_odbc:sql_query(
|
odbc_queries:get_privacy_list_id(LServer, Username, SName).
|
||||||
LServer,
|
|
||||||
["select id from privacy_list "
|
|
||||||
"where username='", Username, "' and name='", SName, "';"]).
|
|
||||||
|
|
||||||
sql_get_privacy_list_id_t(LUser, Name) ->
|
sql_get_privacy_list_id_t(LUser, Name) ->
|
||||||
Username = ejabberd_odbc:escape(LUser),
|
Username = ejabberd_odbc:escape(LUser),
|
||||||
SName = ejabberd_odbc:escape(Name),
|
SName = ejabberd_odbc:escape(Name),
|
||||||
ejabberd_odbc:sql_query_t(
|
odbc_queries:get_privacy_list_id_t(Username, SName).
|
||||||
["select id from privacy_list "
|
|
||||||
"where username='", Username, "' and name='", SName, "';"]).
|
|
||||||
|
|
||||||
sql_get_privacy_list_data(LUser, LServer, Name) ->
|
sql_get_privacy_list_data(LUser, LServer, Name) ->
|
||||||
Username = ejabberd_odbc:escape(LUser),
|
Username = ejabberd_odbc:escape(LUser),
|
||||||
SName = ejabberd_odbc:escape(Name),
|
SName = ejabberd_odbc:escape(Name),
|
||||||
ejabberd_odbc:sql_query(
|
odbc_queries:get_privacy_list_data(LServer, Username, SName).
|
||||||
LServer,
|
|
||||||
["select t, value, action, ord, match_all, match_iq, "
|
|
||||||
"match_message, match_presence_in, match_presence_out "
|
|
||||||
"from privacy_list_data "
|
|
||||||
"where id = (select id from privacy_list where "
|
|
||||||
" username='", Username, "' and name='", SName, "') "
|
|
||||||
"order by ord;"]).
|
|
||||||
|
|
||||||
sql_get_privacy_list_data_by_id(ID, LServer) ->
|
sql_get_privacy_list_data_by_id(ID, LServer) ->
|
||||||
ejabberd_odbc:sql_query(
|
odbc_queries:get_privacy_list_data_by_id(LServer, ID).
|
||||||
LServer,
|
|
||||||
["select t, value, action, ord, match_all, match_iq, "
|
|
||||||
"match_message, match_presence_in, match_presence_out "
|
|
||||||
"from privacy_list_data "
|
|
||||||
"where id='", ID, "' order by ord;"]).
|
|
||||||
|
|
||||||
sql_set_default_privacy_list(LUser, Name) ->
|
sql_set_default_privacy_list(LUser, Name) ->
|
||||||
Username = ejabberd_odbc:escape(LUser),
|
Username = ejabberd_odbc:escape(LUser),
|
||||||
SName = ejabberd_odbc:escape(Name),
|
SName = ejabberd_odbc:escape(Name),
|
||||||
ejabberd_odbc:sql_query_t(
|
odbc_queries:set_default_privacy_list(Username, SName).
|
||||||
["delete from privacy_default_list "
|
|
||||||
" where username='", Username, "';"]),
|
|
||||||
ejabberd_odbc:sql_query_t(
|
|
||||||
["insert into privacy_default_list(username, name) "
|
|
||||||
"values ('", Username, "', '", SName, "');"]).
|
|
||||||
|
|
||||||
sql_unset_default_privacy_list(LUser, LServer) ->
|
sql_unset_default_privacy_list(LUser, LServer) ->
|
||||||
Username = ejabberd_odbc:escape(LUser),
|
Username = ejabberd_odbc:escape(LUser),
|
||||||
ejabberd_odbc:sql_query(
|
odbc_queries:unset_default_privacy_list(LServer, Username).
|
||||||
LServer,
|
|
||||||
["delete from privacy_default_list "
|
|
||||||
" where username='", Username, "';"]).
|
|
||||||
|
|
||||||
sql_remove_privacy_list(LUser, Name) ->
|
sql_remove_privacy_list(LUser, Name) ->
|
||||||
Username = ejabberd_odbc:escape(LUser),
|
Username = ejabberd_odbc:escape(LUser),
|
||||||
SName = ejabberd_odbc:escape(Name),
|
SName = ejabberd_odbc:escape(Name),
|
||||||
ejabberd_odbc:sql_query_t(
|
odbc_queries:remove_privacy_list(Username, SName).
|
||||||
["delete from privacy_list "
|
|
||||||
"where username='", Username, "' and name='", SName, "';"]).
|
|
||||||
|
|
||||||
sql_add_privacy_list(LUser, Name) ->
|
sql_add_privacy_list(LUser, Name) ->
|
||||||
Username = ejabberd_odbc:escape(LUser),
|
Username = ejabberd_odbc:escape(LUser),
|
||||||
SName = ejabberd_odbc:escape(Name),
|
SName = ejabberd_odbc:escape(Name),
|
||||||
ejabberd_odbc:sql_query_t(
|
odbc_queries:add_privacy_list(Username, SName).
|
||||||
["insert into privacy_list(username, name) "
|
|
||||||
"values ('", Username, "', '", SName, "');"]).
|
|
||||||
|
|
||||||
sql_set_privacy_list(ID, RItems) ->
|
sql_set_privacy_list(ID, RItems) ->
|
||||||
ejabberd_odbc:sql_query_t(
|
odbc_queries:set_privacy_list(ID, RItems).
|
||||||
["delete from privacy_list_data "
|
|
||||||
"where id='", ID, "';"]),
|
|
||||||
lists:foreach(fun(Items) ->
|
|
||||||
ejabberd_odbc:sql_query_t(
|
|
||||||
["insert into privacy_list_data("
|
|
||||||
"id, t, value, action, ord, match_all, match_iq, "
|
|
||||||
"match_message, match_presence_in, "
|
|
||||||
"match_presence_out "
|
|
||||||
") "
|
|
||||||
"values ('", ID, "', ", Items, ");"])
|
|
||||||
end, RItems).
|
|
||||||
|
|
||||||
sql_del_privacy_lists(LUser, LServer) ->
|
sql_del_privacy_lists(LUser, LServer) ->
|
||||||
Username = ejabberd_odbc:escape(LUser),
|
Username = ejabberd_odbc:escape(LUser),
|
||||||
Server = ejabberd_odbc:escape(LServer),
|
Server = ejabberd_odbc:escape(LServer),
|
||||||
ejabberd_odbc:sql_query(
|
odbc_queries:del_privacy_lists(LServer, Server, Username).
|
||||||
LServer,
|
|
||||||
["delete from privacy_list where username='", Username, "';"]),
|
|
||||||
ejabberd_odbc:sql_query(
|
|
||||||
LServer,
|
|
||||||
["delete from privacy_list_data where value='", Username++"@"++Server, "';"]),
|
|
||||||
ejabberd_odbc:sql_query(
|
|
||||||
LServer,
|
|
||||||
["delete from privacy_default_list where username='", Username, "';"]).
|
|
||||||
|
@ -640,18 +640,13 @@ remove_user(User, Server) when is_binary(User), is_binary(Server) ->
|
|||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
set_items(User, Server, #xmlel{children = Els}) ->
|
set_items(User, Server, #xmlel{children = Els}) ->
|
||||||
try
|
LUser = exmpp_stringprep:nodeprep(User),
|
||||||
LUser = exmpp_stringprep:nodeprep(User),
|
LServer = exmpp_stringprep:nameprep(Server),
|
||||||
LServer = exmpp_stringprep:nameprep(Server),
|
catch odbc_queries:sql_transaction(
|
||||||
catch odbc_queries:sql_transaction(
|
LServer,
|
||||||
LServer,
|
lists:flatmap(fun(El) ->
|
||||||
lists:flatmap(fun(El) ->
|
process_item_set_t(LUser, LServer, El)
|
||||||
process_item_set_t(LUser, LServer, El)
|
end, Els)).
|
||||||
end, Els))
|
|
||||||
catch
|
|
||||||
_ ->
|
|
||||||
ok
|
|
||||||
end.
|
|
||||||
|
|
||||||
process_item_set_t(LUser, LServer, #xmlel{} = El) ->
|
process_item_set_t(LUser, LServer, #xmlel{} = El) ->
|
||||||
try
|
try
|
||||||
@ -868,13 +863,7 @@ record_to_string(#roster{us = {User, _Server},
|
|||||||
none -> "N"
|
none -> "N"
|
||||||
end,
|
end,
|
||||||
SAskMessage = ejabberd_odbc:escape(binary_to_list(AskMessage)),
|
SAskMessage = ejabberd_odbc:escape(binary_to_list(AskMessage)),
|
||||||
["'", Username, "',"
|
[Username, SJID, Nick, SSubscription, SAsk, SAskMessage, "N", "", "item"].
|
||||||
"'", SJID, "',"
|
|
||||||
"'", Nick, "',"
|
|
||||||
"'", SSubscription, "',"
|
|
||||||
"'", SAsk, "',"
|
|
||||||
"'", SAskMessage, "',"
|
|
||||||
"'N', '', 'item'"].
|
|
||||||
|
|
||||||
groups_to_string(#roster{us = {User, _Server},
|
groups_to_string(#roster{us = {User, _Server},
|
||||||
jid = JID,
|
jid = JID,
|
||||||
@ -885,12 +874,11 @@ groups_to_string(#roster{us = {User, _Server},
|
|||||||
|
|
||||||
%% Empty groups do not need to be converted to string to be inserted in
|
%% Empty groups do not need to be converted to string to be inserted in
|
||||||
%% the database
|
%% the database
|
||||||
lists:foldl(fun([], Acc) -> Acc;
|
lists:foldl(
|
||||||
(Group, Acc) ->
|
fun([], Acc) -> Acc;
|
||||||
String = ["'", Username, "',"
|
(Group, Acc) ->
|
||||||
"'", SJID, "',"
|
G = ejabberd_odbc:escape(binary_to_list(Group)),
|
||||||
"'", ejabberd_odbc:escape(binary_to_list(Group)), "'"],
|
[[Username, SJID, G]|Acc] end, [], Groups).
|
||||||
[String|Acc] end, [], Groups).
|
|
||||||
|
|
||||||
webadmin_page(_, Host,
|
webadmin_page(_, Host,
|
||||||
#request{us = _US,
|
#request{us = _US,
|
||||||
|
@ -55,6 +55,8 @@
|
|||||||
-define(PGSQL_PORT, 5432).
|
-define(PGSQL_PORT, 5432).
|
||||||
-define(MYSQL_PORT, 3306).
|
-define(MYSQL_PORT, 3306).
|
||||||
|
|
||||||
|
-define(TRANSACTION_TIMEOUT, 60000).
|
||||||
|
-define(KEEPALIVE_TIMEOUT, 60000).
|
||||||
-define(KEEPALIVE_QUERY, "SELECT 1;").
|
-define(KEEPALIVE_QUERY, "SELECT 1;").
|
||||||
|
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
@ -68,7 +70,7 @@ start_link(Host, StartInterval) ->
|
|||||||
|
|
||||||
sql_query(Host, Query) ->
|
sql_query(Host, Query) ->
|
||||||
gen_server:call(ejabberd_odbc_sup:get_random_pid(Host),
|
gen_server:call(ejabberd_odbc_sup:get_random_pid(Host),
|
||||||
{sql_query, Query}, 60000).
|
{sql_query, Query}, ?TRANSACTION_TIMEOUT).
|
||||||
|
|
||||||
%% SQL transaction based on a list of queries
|
%% SQL transaction based on a list of queries
|
||||||
%% This function automatically
|
%% This function automatically
|
||||||
@ -83,7 +85,7 @@ sql_transaction(Host, Queries) when is_list(Queries) ->
|
|||||||
%% SQL transaction, based on a erlang anonymous function (F = fun)
|
%% SQL transaction, based on a erlang anonymous function (F = fun)
|
||||||
sql_transaction(Host, F) ->
|
sql_transaction(Host, F) ->
|
||||||
gen_server:call(ejabberd_odbc_sup:get_random_pid(Host),
|
gen_server:call(ejabberd_odbc_sup:get_random_pid(Host),
|
||||||
{sql_transaction, F}, 60000).
|
{sql_transaction, F}, ?TRANSACTION_TIMEOUT).
|
||||||
|
|
||||||
%% This function is intended to be used from inside an sql_transaction:
|
%% This function is intended to be used from inside an sql_transaction:
|
||||||
sql_query_t(Query) ->
|
sql_query_t(Query) ->
|
||||||
@ -93,12 +95,12 @@ sql_query_t(Query) ->
|
|||||||
{error, "No SQL-driver information available."} ->
|
{error, "No SQL-driver information available."} ->
|
||||||
% workaround for odbc bug
|
% workaround for odbc bug
|
||||||
{updated, 0};
|
{updated, 0};
|
||||||
{error, _} ->
|
{error, Reason} ->
|
||||||
throw(aborted);
|
throw({aborted, Reason});
|
||||||
Rs when is_list(Rs) ->
|
Rs when is_list(Rs) ->
|
||||||
case lists:keymember(error, 1, Rs) of
|
case lists:keysearch(error, 1, Rs) of
|
||||||
true ->
|
{value, {error, Reason}} ->
|
||||||
throw(aborted);
|
throw({aborted, Reason});
|
||||||
_ ->
|
_ ->
|
||||||
QRes
|
QRes
|
||||||
end;
|
end;
|
||||||
@ -177,7 +179,7 @@ handle_call({sql_query, Query}, _From, State) ->
|
|||||||
{reply, Reply, State}
|
{reply, Reply, State}
|
||||||
end;
|
end;
|
||||||
handle_call({sql_transaction, F}, _From, State) ->
|
handle_call({sql_transaction, F}, _From, State) ->
|
||||||
case execute_transaction(State, F, ?MAX_TRANSACTION_RESTARTS) of
|
case execute_transaction(State, F, ?MAX_TRANSACTION_RESTARTS, "") of
|
||||||
% error returned by MySQL driver
|
% error returned by MySQL driver
|
||||||
{error, "query timed out"} ->
|
{error, "query timed out"} ->
|
||||||
{stop, timeout, State};
|
{stop, timeout, State};
|
||||||
@ -247,14 +249,22 @@ sql_query_internal(State, Query) ->
|
|||||||
mysql_to_odbc(mysql_conn:fetch(State#state.db_ref, Query, self()))
|
mysql_to_odbc(mysql_conn:fetch(State#state.db_ref, Query, self()))
|
||||||
end.
|
end.
|
||||||
|
|
||||||
execute_transaction(_State, _F, 0) ->
|
execute_transaction(State, _F, 0, Reason) ->
|
||||||
|
?ERROR_MSG("SQL transaction restarts exceeded~n"
|
||||||
|
"** Restarts: ~p~n"
|
||||||
|
"** Last abort reason: ~p~n"
|
||||||
|
"** Stacktrace: ~p~n"
|
||||||
|
"** When State == ~p",
|
||||||
|
[?MAX_TRANSACTION_RESTARTS, Reason,
|
||||||
|
erlang:get_stacktrace(), State]),
|
||||||
|
sql_query_internal(State, "rollback;"),
|
||||||
{aborted, restarts_exceeded};
|
{aborted, restarts_exceeded};
|
||||||
execute_transaction(State, F, NRestarts) ->
|
execute_transaction(State, F, NRestarts, _Reason) ->
|
||||||
put(?STATE_KEY, State),
|
put(?STATE_KEY, State),
|
||||||
sql_query_internal(State, "begin;"),
|
sql_query_internal(State, "begin;"),
|
||||||
case catch F() of
|
case catch F() of
|
||||||
aborted ->
|
{aborted, Reason} ->
|
||||||
execute_transaction(State, F, NRestarts - 1);
|
execute_transaction(State, F, NRestarts - 1, Reason);
|
||||||
{'EXIT', Reason} ->
|
{'EXIT', Reason} ->
|
||||||
sql_query_internal(State, "rollback;"),
|
sql_query_internal(State, "rollback;"),
|
||||||
{aborted, Reason};
|
{aborted, Reason};
|
||||||
@ -330,11 +340,6 @@ mysql_connect(Server, Port, DB, Username, Password, StartInterval) ->
|
|||||||
{ok, Ref} ->
|
{ok, Ref} ->
|
||||||
erlang:monitor(process, Ref),
|
erlang:monitor(process, Ref),
|
||||||
mysql_conn:fetch(Ref, ["set names 'utf8';"], self()),
|
mysql_conn:fetch(Ref, ["set names 'utf8';"], self()),
|
||||||
% needed to ensure the order of queries, specifically at
|
|
||||||
% roster subscription time (this can also be set-up in the
|
|
||||||
% MySQL configuration, but not at the database level):
|
|
||||||
mysql_conn:fetch(Ref, ["SET SESSION TRANSACTION ISOLATION LEVEL "
|
|
||||||
"SERIALIZABLE;"], self()),
|
|
||||||
{ok, #state{db_ref = Ref, db_type = mysql}};
|
{ok, #state{db_ref = Ref, db_type = mysql}};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?ERROR_MSG("MySQL connection failed: ~p~nWaiting ~p seconds before retrying...~n",
|
?ERROR_MSG("MySQL connection failed: ~p~nWaiting ~p seconds before retrying...~n",
|
||||||
@ -365,7 +370,7 @@ mysql_item_to_odbc(Columns, Recs) ->
|
|||||||
|
|
||||||
% perform a harmless query on all opened connexions to avoid connexion close.
|
% perform a harmless query on all opened connexions to avoid connexion close.
|
||||||
keep_alive(PID) ->
|
keep_alive(PID) ->
|
||||||
gen_server:call(PID, {sql_query, ?KEEPALIVE_QUERY}, 60000).
|
gen_server:call(PID, {sql_query, ?KEEPALIVE_QUERY}, ?KEEPALIVE_TIMEOUT).
|
||||||
|
|
||||||
% log function used by MySQL driver
|
% log function used by MySQL driver
|
||||||
log(Level, Format, Args) ->
|
log(Level, Format, Args) ->
|
||||||
|
@ -61,6 +61,20 @@
|
|||||||
set_private_data_sql/3,
|
set_private_data_sql/3,
|
||||||
get_private_data/3,
|
get_private_data/3,
|
||||||
del_user_private_storage/2,
|
del_user_private_storage/2,
|
||||||
|
get_default_privacy_list/2,
|
||||||
|
get_default_privacy_list_t/1,
|
||||||
|
get_privacy_list_names/2,
|
||||||
|
get_privacy_list_names_t/1,
|
||||||
|
get_privacy_list_id/3,
|
||||||
|
get_privacy_list_id_t/2,
|
||||||
|
get_privacy_list_data/3,
|
||||||
|
get_privacy_list_data_by_id/2,
|
||||||
|
set_default_privacy_list/2,
|
||||||
|
unset_default_privacy_list/2,
|
||||||
|
remove_privacy_list/2,
|
||||||
|
add_privacy_list/2,
|
||||||
|
set_privacy_list/2,
|
||||||
|
del_privacy_lists/3,
|
||||||
set_vcard/26,
|
set_vcard/26,
|
||||||
get_vcard/2,
|
get_vcard/2,
|
||||||
escape/1,
|
escape/1,
|
||||||
@ -74,6 +88,14 @@
|
|||||||
-define(generic, true).
|
-define(generic, true).
|
||||||
-endif.
|
-endif.
|
||||||
|
|
||||||
|
%% Almost a copy of string:join/2.
|
||||||
|
%% We use this version because string:join/2 is relatively
|
||||||
|
%% new function (introduced in R12B-0).
|
||||||
|
join([], _Sep) ->
|
||||||
|
[];
|
||||||
|
join([H|T], Sep) ->
|
||||||
|
[H, [[Sep, X] || X <- T]].
|
||||||
|
|
||||||
%% -----------------
|
%% -----------------
|
||||||
%% Generic queries
|
%% Generic queries
|
||||||
-ifdef(generic).
|
-ifdef(generic).
|
||||||
@ -81,9 +103,25 @@
|
|||||||
get_db_type() ->
|
get_db_type() ->
|
||||||
generic.
|
generic.
|
||||||
|
|
||||||
|
%% Safe atomic update.
|
||||||
|
update_t(Table, Fields, Vals, Where) ->
|
||||||
|
UPairs = lists:zipwith(fun(A, B) -> A ++ "='" ++ B ++ "'" end,
|
||||||
|
Fields, Vals),
|
||||||
|
case ejabberd_odbc:sql_query_t(
|
||||||
|
["update ", Table, " set ",
|
||||||
|
join(UPairs, ", "),
|
||||||
|
" where ", Where, ";"]) of
|
||||||
|
{updated, 1} ->
|
||||||
|
ok;
|
||||||
|
_ ->
|
||||||
|
ejabberd_odbc:sql_query_t(
|
||||||
|
["insert into ", Table, "(", join(Fields, ", "),
|
||||||
|
") values ('", join(Vals, "', '"), "');"])
|
||||||
|
end.
|
||||||
|
|
||||||
%% F can be either a fun or a list of queries
|
%% F can be either a fun or a list of queries
|
||||||
%% TODO: We should probably move the list of queries transaction wrapper from the ejabberd_odbc module
|
%% TODO: We should probably move the list of queries transaction
|
||||||
%% to this one (odbc_queries)
|
%% wrapper from the ejabberd_odbc module to this one (odbc_queries)
|
||||||
sql_transaction(LServer, F) ->
|
sql_transaction(LServer, F) ->
|
||||||
ejabberd_odbc:sql_transaction(LServer, F).
|
ejabberd_odbc:sql_transaction(LServer, F).
|
||||||
|
|
||||||
@ -97,9 +135,11 @@ set_last_t(LServer, Username, Seconds, State) ->
|
|||||||
%% MREMOND: I think this should be turn into a non transactional behaviour
|
%% MREMOND: I think this should be turn into a non transactional behaviour
|
||||||
ejabberd_odbc:sql_transaction(
|
ejabberd_odbc:sql_transaction(
|
||||||
LServer,
|
LServer,
|
||||||
[["delete from last where username='", Username, "';"],
|
fun() ->
|
||||||
["insert into last(username, seconds, state) "
|
update_t("last", ["username", "seconds", "state"],
|
||||||
"values ('", Username, "', '", Seconds, "', '", State, "');"]]).
|
[Username, Seconds, State],
|
||||||
|
["username='", Username, "'"])
|
||||||
|
end).
|
||||||
|
|
||||||
del_last(LServer, Username) ->
|
del_last(LServer, Username) ->
|
||||||
ejabberd_odbc:sql_query(
|
ejabberd_odbc:sql_query(
|
||||||
@ -115,9 +155,11 @@ get_password(LServer, Username) ->
|
|||||||
set_password_t(LServer, Username, Pass) ->
|
set_password_t(LServer, Username, Pass) ->
|
||||||
ejabberd_odbc:sql_transaction(
|
ejabberd_odbc:sql_transaction(
|
||||||
LServer,
|
LServer,
|
||||||
[["delete from users where username='", Username ,"';"],
|
fun() ->
|
||||||
["insert into users(username, password) "
|
update_t("users", ["username", "password"],
|
||||||
"values ('", Username, "', '", Pass, "');"]]).
|
[Username, Pass],
|
||||||
|
["username='", Username ,"'"])
|
||||||
|
end).
|
||||||
|
|
||||||
add_user(LServer, Username, Pass) ->
|
add_user(LServer, Username, Pass) ->
|
||||||
ejabberd_odbc:sql_query(
|
ejabberd_odbc:sql_query(
|
||||||
@ -296,16 +338,11 @@ del_roster_sql(Username, SJID) ->
|
|||||||
" and jid='", SJID, "';"]].
|
" and jid='", SJID, "';"]].
|
||||||
|
|
||||||
update_roster(_LServer, Username, SJID, ItemVals, ItemGroups) ->
|
update_roster(_LServer, Username, SJID, ItemVals, ItemGroups) ->
|
||||||
ejabberd_odbc:sql_query_t(
|
update_t("rosterusers",
|
||||||
["delete from rosterusers "
|
["username", "jid", "nick", "subscription", "ask",
|
||||||
" where username='", Username, "' "
|
"askmessage", "server", "subscribe", "type"],
|
||||||
" and jid='", SJID, "';"]),
|
ItemVals,
|
||||||
ejabberd_odbc:sql_query_t(
|
["username='", Username, "' and jid='", SJID, "'"]),
|
||||||
["insert into rosterusers("
|
|
||||||
" username, jid, nick, "
|
|
||||||
" subscription, ask, askmessage, "
|
|
||||||
" server, subscribe, type) "
|
|
||||||
" values (", ItemVals, ");"]),
|
|
||||||
ejabberd_odbc:sql_query_t(
|
ejabberd_odbc:sql_query_t(
|
||||||
["delete from rostergroups "
|
["delete from rostergroups "
|
||||||
" where username='", Username, "' "
|
" where username='", Username, "' "
|
||||||
@ -314,7 +351,7 @@ update_roster(_LServer, Username, SJID, ItemVals, ItemGroups) ->
|
|||||||
ejabberd_odbc:sql_query_t(
|
ejabberd_odbc:sql_query_t(
|
||||||
["insert into rostergroups("
|
["insert into rostergroups("
|
||||||
" username, jid, grp) "
|
" username, jid, grp) "
|
||||||
" values (", ItemGroup, ");"])
|
" values ('", join(ItemGroup, "', '"), "');"])
|
||||||
end,
|
end,
|
||||||
ItemGroups).
|
ItemGroups).
|
||||||
|
|
||||||
@ -326,26 +363,21 @@ update_roster_sql(Username, SJID, ItemVals, ItemGroups) ->
|
|||||||
" username, jid, nick, "
|
" username, jid, nick, "
|
||||||
" subscription, ask, askmessage, "
|
" subscription, ask, askmessage, "
|
||||||
" server, subscribe, type) "
|
" server, subscribe, type) "
|
||||||
" values (", ItemVals, ");"],
|
" values ('", join(ItemVals, "', '"), "');"],
|
||||||
["delete from rostergroups "
|
["delete from rostergroups "
|
||||||
" where username='", Username, "' "
|
" where username='", Username, "' "
|
||||||
" and jid='", SJID, "';"]] ++
|
" and jid='", SJID, "';"]] ++
|
||||||
[["insert into rostergroups("
|
[["insert into rostergroups("
|
||||||
" username, jid, grp) "
|
" username, jid, grp) "
|
||||||
" values (", ItemGroup, ");"] ||
|
" values ('", join(ItemGroup, "', '"), "');"] ||
|
||||||
ItemGroup <- ItemGroups].
|
ItemGroup <- ItemGroups].
|
||||||
|
|
||||||
roster_subscribe(_LServer, Username, SJID, ItemVals) ->
|
roster_subscribe(_LServer, Username, SJID, ItemVals) ->
|
||||||
ejabberd_odbc:sql_query_t(
|
update_t("rosterusers",
|
||||||
["delete from rosterusers "
|
["username", "jid", "nick", "subscription", "ask",
|
||||||
" where username='", Username, "' "
|
"askmessage", "server", "subscribe", "type"],
|
||||||
" and jid='", SJID, "';"]),
|
ItemVals,
|
||||||
ejabberd_odbc:sql_query_t(
|
["username='", Username, "' and jid='", SJID, "'"]).
|
||||||
["insert into rosterusers("
|
|
||||||
" username, jid, nick, "
|
|
||||||
" subscription, ask, askmessage, "
|
|
||||||
" server, subscribe, type) "
|
|
||||||
" values (", ItemVals, ");"]).
|
|
||||||
|
|
||||||
get_subscription(LServer, Username, SJID) ->
|
get_subscription(LServer, Username, SJID) ->
|
||||||
ejabberd_odbc:sql_query(
|
ejabberd_odbc:sql_query(
|
||||||
@ -355,10 +387,10 @@ get_subscription(LServer, Username, SJID) ->
|
|||||||
"and jid='", SJID, "'"]).
|
"and jid='", SJID, "'"]).
|
||||||
|
|
||||||
set_private_data(_LServer, Username, LXMLNS, SData) ->
|
set_private_data(_LServer, Username, LXMLNS, SData) ->
|
||||||
lists:foreach(fun(Query) ->
|
update_t("private_storage",
|
||||||
ejabberd_odbc:sql_query_t(Query)
|
["username", "namespace", "data"],
|
||||||
end,
|
[Username, LXMLNS, SData],
|
||||||
set_private_data_sql(Username, LXMLNS, SData)).
|
["username='", Username, "' and namespace='", LXMLNS, "'"]).
|
||||||
|
|
||||||
set_private_data_sql(Username, LXMLNS, SData) ->
|
set_private_data_sql(Username, LXMLNS, SData) ->
|
||||||
[["delete from private_storage "
|
[["delete from private_storage "
|
||||||
@ -380,35 +412,29 @@ del_user_private_storage(LServer, Username) ->
|
|||||||
LServer,
|
LServer,
|
||||||
["delete from private_storage where username='", Username, "';"]).
|
["delete from private_storage where username='", Username, "';"]).
|
||||||
|
|
||||||
|
|
||||||
set_vcard(LServer, LUsername, SBDay, SCTRY, SEMail, SFN, SFamily, SGiven,
|
set_vcard(LServer, LUsername, SBDay, SCTRY, SEMail, SFN, SFamily, SGiven,
|
||||||
SLBDay, SLCTRY, SLEMail, SLFN, SLFamily, SLGiven, SLLocality,
|
SLBDay, SLCTRY, SLEMail, SLFN, SLFamily, SLGiven, SLLocality,
|
||||||
SLMiddle, SLNickname, SLOrgName, SLOrgUnit, SLocality, SMiddle,
|
SLMiddle, SLNickname, SLOrgName, SLOrgUnit, SLocality, SMiddle,
|
||||||
SNickname, SOrgName, SOrgUnit, SVCARD, Username) ->
|
SNickname, SOrgName, SOrgUnit, SVCARD, Username) ->
|
||||||
ejabberd_odbc:sql_transaction(
|
ejabberd_odbc:sql_transaction(
|
||||||
LServer,
|
LServer,
|
||||||
[["delete from vcard where username='", LUsername, "';"],
|
fun() ->
|
||||||
["insert into vcard(username, vcard) "
|
update_t("vcard", ["username", "vcard"],
|
||||||
"values ('", LUsername, "', '", SVCARD, "');"],
|
[LUsername, SVCARD],
|
||||||
["delete from vcard_search where lusername='", LUsername, "';"],
|
["username='", LUsername, "'"]),
|
||||||
["insert into vcard_search("
|
update_t("vcard_search",
|
||||||
" username, lusername, fn, lfn, family, lfamily,"
|
["username", "lusername", "fn", "lfn", "family",
|
||||||
" given, lgiven, middle, lmiddle, nickname, lnickname,"
|
"lfamily", "given", "lgiven", "middle", "lmiddle",
|
||||||
" bday, lbday, ctry, lctry, locality, llocality,"
|
"nickname", "lnickname", "bday", "lbday", "ctry",
|
||||||
" email, lemail, orgname, lorgname, orgunit, lorgunit)"
|
"lctry", "locality", "llocality", "email", "lemail",
|
||||||
"values (",
|
"orgname", "lorgname", "orgunit", "lorgunit"],
|
||||||
" '", Username, "', '", LUsername, "',"
|
[Username, LUsername, SFN, SLFN, SFamily, SLFamily,
|
||||||
" '", SFN, "', '", SLFN, "',"
|
SGiven, SLGiven, SMiddle, SLMiddle, SNickname,
|
||||||
" '", SFamily, "', '", SLFamily, "',"
|
SLNickname, SBDay, SLBDay, SCTRY, SLCTRY,
|
||||||
" '", SGiven, "', '", SLGiven, "',"
|
SLocality, SLLocality, SEMail, SLEMail, SOrgName,
|
||||||
" '", SMiddle, "', '", SLMiddle, "',"
|
SLOrgName, SOrgUnit, SLOrgUnit],
|
||||||
" '", SNickname, "', '", SLNickname, "',"
|
["lusername='", LUsername, "'"])
|
||||||
" '", SBDay, "', '", SLBDay, "',"
|
end).
|
||||||
" '", SCTRY, "', '", SLCTRY, "',"
|
|
||||||
" '", SLocality, "', '", SLLocality, "',"
|
|
||||||
" '", SEMail, "', '", SLEMail, "',"
|
|
||||||
" '", SOrgName, "', '", SLOrgName, "',"
|
|
||||||
" '", SOrgUnit, "', '", SLOrgUnit, "');"]]).
|
|
||||||
|
|
||||||
get_vcard(LServer, Username) ->
|
get_vcard(LServer, Username) ->
|
||||||
ejabberd_odbc:sql_query(
|
ejabberd_odbc:sql_query(
|
||||||
@ -416,6 +442,103 @@ get_vcard(LServer, Username) ->
|
|||||||
["select vcard from vcard "
|
["select vcard from vcard "
|
||||||
"where username='", Username, "';"]).
|
"where username='", Username, "';"]).
|
||||||
|
|
||||||
|
get_default_privacy_list(LServer, Username) ->
|
||||||
|
ejabberd_odbc:sql_query(
|
||||||
|
LServer,
|
||||||
|
["select name from privacy_default_list "
|
||||||
|
"where username='", Username, "';"]).
|
||||||
|
|
||||||
|
get_default_privacy_list_t(Username) ->
|
||||||
|
ejabberd_odbc:sql_query_t(
|
||||||
|
["select name from privacy_default_list "
|
||||||
|
"where username='", Username, "';"]).
|
||||||
|
|
||||||
|
get_privacy_list_names(LServer, Username) ->
|
||||||
|
ejabberd_odbc:sql_query(
|
||||||
|
LServer,
|
||||||
|
["select name from privacy_list "
|
||||||
|
"where username='", Username, "';"]).
|
||||||
|
|
||||||
|
get_privacy_list_names_t(Username) ->
|
||||||
|
ejabberd_odbc:sql_query_t(
|
||||||
|
["select name from privacy_list "
|
||||||
|
"where username='", Username, "';"]).
|
||||||
|
|
||||||
|
get_privacy_list_id(LServer, Username, SName) ->
|
||||||
|
ejabberd_odbc:sql_query(
|
||||||
|
LServer,
|
||||||
|
["select id from privacy_list "
|
||||||
|
"where username='", Username, "' and name='", SName, "';"]).
|
||||||
|
|
||||||
|
get_privacy_list_id_t(Username, SName) ->
|
||||||
|
ejabberd_odbc:sql_query_t(
|
||||||
|
["select id from privacy_list "
|
||||||
|
"where username='", Username, "' and name='", SName, "';"]).
|
||||||
|
|
||||||
|
get_privacy_list_data(LServer, Username, SName) ->
|
||||||
|
ejabberd_odbc:sql_query(
|
||||||
|
LServer,
|
||||||
|
["select t, value, action, ord, match_all, match_iq, "
|
||||||
|
"match_message, match_presence_in, match_presence_out "
|
||||||
|
"from privacy_list_data "
|
||||||
|
"where id = (select id from privacy_list where "
|
||||||
|
" username='", Username, "' and name='", SName, "') "
|
||||||
|
"order by ord;"]).
|
||||||
|
|
||||||
|
get_privacy_list_data_by_id(LServer, ID) ->
|
||||||
|
ejabberd_odbc:sql_query(
|
||||||
|
LServer,
|
||||||
|
["select t, value, action, ord, match_all, match_iq, "
|
||||||
|
"match_message, match_presence_in, match_presence_out "
|
||||||
|
"from privacy_list_data "
|
||||||
|
"where id='", ID, "' order by ord;"]).
|
||||||
|
|
||||||
|
set_default_privacy_list(Username, SName) ->
|
||||||
|
update_t("privacy_default_list", ["username", "name"],
|
||||||
|
[Username, SName], ["username='", Username, "'"]).
|
||||||
|
|
||||||
|
unset_default_privacy_list(LServer, Username) ->
|
||||||
|
ejabberd_odbc:sql_query(
|
||||||
|
LServer,
|
||||||
|
["delete from privacy_default_list "
|
||||||
|
" where username='", Username, "';"]).
|
||||||
|
|
||||||
|
remove_privacy_list(Username, SName) ->
|
||||||
|
ejabberd_odbc:sql_query_t(
|
||||||
|
["delete from privacy_list "
|
||||||
|
"where username='", Username, "' and name='", SName, "';"]).
|
||||||
|
|
||||||
|
add_privacy_list(Username, SName) ->
|
||||||
|
ejabberd_odbc:sql_query_t(
|
||||||
|
["insert into privacy_list(username, name) "
|
||||||
|
"values ('", Username, "', '", SName, "');"]).
|
||||||
|
|
||||||
|
set_privacy_list(ID, RItems) ->
|
||||||
|
ejabberd_odbc:sql_query_t(
|
||||||
|
["delete from privacy_list_data "
|
||||||
|
"where id='", ID, "';"]),
|
||||||
|
lists:foreach(fun(Items) ->
|
||||||
|
ejabberd_odbc:sql_query_t(
|
||||||
|
["insert into privacy_list_data("
|
||||||
|
"id, t, value, action, ord, match_all, match_iq, "
|
||||||
|
"match_message, match_presence_in, "
|
||||||
|
"match_presence_out "
|
||||||
|
") "
|
||||||
|
"values ('", ID, "', '",
|
||||||
|
join(Items, "', '"), "');"])
|
||||||
|
end, RItems).
|
||||||
|
|
||||||
|
del_privacy_lists(LServer, Server, Username) ->
|
||||||
|
ejabberd_odbc:sql_query(
|
||||||
|
LServer,
|
||||||
|
["delete from privacy_list where username='", Username, "';"]),
|
||||||
|
ejabberd_odbc:sql_query(
|
||||||
|
LServer,
|
||||||
|
["delete from privacy_list_data where value='", Username++"@"++Server, "';"]),
|
||||||
|
ejabberd_odbc:sql_query(
|
||||||
|
LServer,
|
||||||
|
["delete from privacy_default_list where username='", Username, "';"]).
|
||||||
|
|
||||||
%% Characters to escape
|
%% Characters to escape
|
||||||
escape($\0) -> "\\0";
|
escape($\0) -> "\\0";
|
||||||
escape($\n) -> "\\n";
|
escape($\n) -> "\\n";
|
||||||
|
@ -1447,15 +1447,24 @@ user_info(User, Server, Query, Lang) ->
|
|||||||
_ ->
|
_ ->
|
||||||
[?XE('ul',
|
[?XE('ul',
|
||||||
lists:map(fun(R) ->
|
lists:map(fun(R) ->
|
||||||
FIP = case ejabberd_sm:get_user_ip(
|
FIP = case ejabberd_sm:get_user_info(
|
||||||
User, Server, R) of
|
User, Server, R) of
|
||||||
undefined ->
|
offline ->
|
||||||
"";
|
"";
|
||||||
{IP, Port} ->
|
[{node, Node}, {conn, Conn}, {ip, {IP, Port}}] ->
|
||||||
|
ConnS = case Conn of
|
||||||
|
c2s -> "plain";
|
||||||
|
c2s_tls -> "tls";
|
||||||
|
c2s_compressed -> "zlib";
|
||||||
|
http_bind -> "http-bind";
|
||||||
|
http_poll -> "http-poll"
|
||||||
|
end,
|
||||||
" (" ++
|
" (" ++
|
||||||
|
ConnS ++ "://" ++
|
||||||
inet_parse:ntoa(IP) ++
|
inet_parse:ntoa(IP) ++
|
||||||
":" ++
|
":" ++
|
||||||
integer_to_list(Port)
|
integer_to_list(Port)
|
||||||
|
++ "#" ++ atom_to_list(Node)
|
||||||
++ ")"
|
++ ")"
|
||||||
end,
|
end,
|
||||||
?LI([?C(R ++ FIP)])
|
?LI([?C(R ++ FIP)])
|
||||||
|
Loading…
Reference in New Issue
Block a user