mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-22 16:20:52 +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>
|
||||
|
||||
* 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
|
||||
"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>
|
||||
|
||||
* 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.
|
||||
</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.
|
||||
</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">
|
||||
The default policy for incoming and outgoing s2s connections to other Jabber servers.
|
||||
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
|
||||
<TT><resource></TT>. Example:
|
||||
<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
|
||||
matches <TT><regexp></TT> on local virtual hosts. Example:
|
||||
<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.
|
||||
\titem{\{domain\_certfile, Domain, Path\}} \ind{options!domain\_certfile}
|
||||
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\}}
|
||||
The default policy for incoming and outgoing s2s connections to other Jabber servers.
|
||||
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_LIBS")
|
||||
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
|
||||
expat_save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $EXPAT_CFLAGS"
|
||||
@ -36,6 +36,7 @@ AC_DEFUN(AM_WITH_ZLIB,
|
||||
[ AC_ARG_WITH(zlib,
|
||||
[AC_HELP_STRING([--with-zlib=PREFIX], [prefix where zlib is installed])])
|
||||
|
||||
if test x"$ejabberd_zlib" != x; then
|
||||
ZLIB_CFLAGS=
|
||||
ZLIB_LIBS=
|
||||
if test x"$with_zlib" != x; then
|
||||
@ -49,7 +50,7 @@ AC_DEFUN(AM_WITH_ZLIB,
|
||||
[ zlib_found=no ],
|
||||
"$ZLIB_LIBS")
|
||||
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
|
||||
zlib_save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $ZLIB_CFLAGS"
|
||||
@ -57,19 +58,20 @@ AC_DEFUN(AM_WITH_ZLIB,
|
||||
CPPFLAGS="$CPPFLAGS $ZLIB_CFLAGS"
|
||||
AC_CHECK_HEADERS(zlib.h, , zlib_found=no)
|
||||
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
|
||||
CFLAGS="$zlib_save_CFLAGS"
|
||||
CPPFLAGS="$zlib_save_CPPFLAGS"
|
||||
|
||||
AC_SUBST(ZLIB_CFLAGS)
|
||||
AC_SUBST(ZLIB_LIBS)
|
||||
fi
|
||||
])
|
||||
|
||||
AC_DEFUN(AM_WITH_PAM,
|
||||
[ AC_ARG_WITH(pam,
|
||||
[AC_HELP_STRING([--with-pam=PREFIX], [prefix where PAM is installed])])
|
||||
|
||||
if test x"$pam" != x; then
|
||||
PAM_CFLAGS=
|
||||
PAM_LIBS=
|
||||
if test x"$with_pam" != x; then
|
||||
@ -83,7 +85,7 @@ AC_DEFUN(AM_WITH_PAM,
|
||||
[ pam_found=no ],
|
||||
"$PAM_LIBS")
|
||||
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
|
||||
pam_save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $PAM_CFLAGS"
|
||||
@ -91,13 +93,14 @@ AC_DEFUN(AM_WITH_PAM,
|
||||
CPPFLAGS="$CPPFLAGS $PAM_CFLAGS"
|
||||
AC_CHECK_HEADERS(security/pam_appl.h, , pam_found=no)
|
||||
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
|
||||
CFLAGS="$pam_save_CFLAGS"
|
||||
CPPFLAGS="$pam_save_CPPFLAGS"
|
||||
|
||||
AC_SUBST(PAM_CFLAGS)
|
||||
AC_SUBST(PAM_LIBS)
|
||||
fi
|
||||
])
|
||||
|
||||
AC_DEFUN(AM_WITH_ERLANG,
|
||||
@ -346,7 +349,7 @@ if test x"$tls" != x; then
|
||||
fi
|
||||
done
|
||||
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
|
||||
AC_SUBST(SSL_LIBS)
|
||||
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
|
||||
#locating libexpat
|
||||
AM_WITH_EXPAT
|
||||
#locating zlib
|
||||
AM_WITH_ZLIB
|
||||
#locating PAM
|
||||
AM_WITH_PAM
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
@ -36,16 +32,22 @@ AC_PREFIX_DEFAULT(/)
|
||||
AC_FUNC_MALLOC
|
||||
AC_HEADER_STDC
|
||||
|
||||
AC_MOD_ENABLE(mod_pubsub, yes)
|
||||
AC_MOD_ENABLE(mod_irc, yes)
|
||||
AC_MOD_ENABLE(mod_muc, yes)
|
||||
AC_MOD_ENABLE(mod_proxy65, yes)
|
||||
AC_MOD_ENABLE(mod_pubsub, 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(tls, yes)
|
||||
AC_MOD_ENABLE(web, 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_HELP_STRING([--enable-hipe], [compile natively with HiPE, not recommended (default: no)])],
|
||||
|
@ -186,6 +186,13 @@
|
||||
%%{{s2s_host, "goodhost.org"}, allow}.
|
||||
%%{{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
|
||||
|
@ -1890,14 +1890,26 @@ check_from(El, FromJID) ->
|
||||
case exmpp_stanza:get_sender(El) of
|
||||
undefined ->
|
||||
El;
|
||||
SJID ->
|
||||
{value, SJID} ->
|
||||
try
|
||||
JID = exmpp_jid:binary_to_jid(SJID),
|
||||
case exmpp_jid:compare_jids(JID, FromJID) of
|
||||
JIDEl = exmpp_jid:parse_jid(SJID),
|
||||
case exmpp_jid:lresource(JIDEl) of
|
||||
undefined ->
|
||||
%% Matching JID: The stanza is ok
|
||||
case exmpp_jid:compare_bare_jids(JIDEl, FromJID) of
|
||||
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
|
||||
catch
|
||||
_:_ ->
|
||||
|
@ -331,6 +331,8 @@ process_term(Term, State) ->
|
||||
add_option(language, Val, State);
|
||||
{outgoing_s2s_port, Port} ->
|
||||
add_option(outgoing_s2s_port, Port, State);
|
||||
{outgoing_s2s_options, Methods, Timeout} ->
|
||||
add_option(outgoing_s2s_options, {Methods, Timeout}, State);
|
||||
{s2s_use_starttls, Port} ->
|
||||
add_option(s2s_use_starttls, Port, State);
|
||||
{s2s_certfile, CertFile} ->
|
||||
|
@ -108,6 +108,8 @@
|
||||
]).
|
||||
|
||||
|
||||
-define(SOCKET_DEFAULT_RESULT, {error, badarg}).
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% API
|
||||
%%%----------------------------------------------------------------------
|
||||
@ -195,7 +197,7 @@ open_socket(init, StateData) ->
|
||||
_ ->
|
||||
open_socket1(Addr, Port)
|
||||
end
|
||||
end, {error, badarg}, AddrList) of
|
||||
end, ?SOCKET_DEFAULT_RESULT, AddrList) of
|
||||
{ok, Socket} ->
|
||||
Version = if
|
||||
StateData#state.use_v10 ->
|
||||
@ -231,34 +233,40 @@ open_socket(_, StateData) ->
|
||||
{next_state, open_socket, StateData}.
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
open_socket1(Addr, Port) ->
|
||||
?DEBUG("s2s_out: connecting to ~s:~p~n", [Addr, Port]),
|
||||
Res = case catch ejabberd_socket:connect(
|
||||
Addr, Port,
|
||||
%% IPv4
|
||||
open_socket1({_,_,_,_} = Addr, Port) ->
|
||||
open_socket2(inet, Addr, Port);
|
||||
|
||||
%% IPv6
|
||||
open_socket1({_,_,_,_,_,_,_,_} = Addr, Port) ->
|
||||
open_socket2(inet6, Addr, Port);
|
||||
|
||||
%% Hostname
|
||||
open_socket1(Host, Port) ->
|
||||
lists:foldl(fun(_Family, {ok, _Socket} = R) ->
|
||||
R;
|
||||
(Family, _) ->
|
||||
Addrs = get_addrs(Host, Family),
|
||||
lists:foldl(fun(_Addr, {ok, _Socket} = R) ->
|
||||
R;
|
||||
(Addr, _) ->
|
||||
open_socket1(Addr, Port)
|
||||
end, ?SOCKET_DEFAULT_RESULT, Addrs)
|
||||
end, ?SOCKET_DEFAULT_RESULT, outgoing_s2s_families()).
|
||||
|
||||
open_socket2(Type, Addr, Port) ->
|
||||
?DEBUG("s2s_out: connecting to ~p:~p~n", [Addr, Port]),
|
||||
Timeout = outgoing_s2s_timeout(),
|
||||
case (catch ejabberd_socket:connect(Addr, Port,
|
||||
[binary, {packet, 0},
|
||||
{active, false}]) of
|
||||
{active, false}, Type],
|
||||
Timeout)) of
|
||||
{ok, _Socket} = R -> R;
|
||||
{error, Reason1} ->
|
||||
?DEBUG("s2s_out: connect return ~p~n", [Reason1]),
|
||||
catch ejabberd_socket:connect(
|
||||
Addr, Port,
|
||||
[binary, {packet, 0},
|
||||
{active, false}, inet6]);
|
||||
{'EXIT', Reason1} ->
|
||||
?DEBUG("s2s_out: connect crashed ~p~n", [Reason1]),
|
||||
catch ejabberd_socket:connect(
|
||||
Addr, Port,
|
||||
[binary, {packet, 0},
|
||||
{active, false}, inet6])
|
||||
end,
|
||||
case Res of
|
||||
{ok, Socket} ->
|
||||
{ok, Socket};
|
||||
{error, Reason} ->
|
||||
?DEBUG("s2s_out: inet6 connect return ~p~n", [Reason]),
|
||||
{error, Reason};
|
||||
{error, Reason} = R ->
|
||||
?DEBUG("s2s_out: connect return ~p~n", [Reason]),
|
||||
R;
|
||||
{'EXIT', Reason} ->
|
||||
?DEBUG("s2s_out: inet6 connect crashed ~p~n", [Reason]),
|
||||
?DEBUG("s2s_out: connect crashed ~p~n", [Reason]),
|
||||
{error, Reason}
|
||||
end.
|
||||
|
||||
@ -953,6 +961,23 @@ test_get_addr_port(Server) ->
|
||||
end
|
||||
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() ->
|
||||
case ejabberd_config:get_local_option(outgoing_s2s_port) of
|
||||
Port when is_integer(Port) ->
|
||||
@ -961,6 +986,36 @@ outgoing_s2s_port() ->
|
||||
5269
|
||||
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
|
||||
%% Do not log dialback
|
||||
log_s2s_out(false, _, _) -> ok;
|
||||
|
@ -30,6 +30,7 @@
|
||||
%% API
|
||||
-export([start/4,
|
||||
connect/3,
|
||||
connect/4,
|
||||
starttls/2,
|
||||
starttls/3,
|
||||
compress/1,
|
||||
@ -94,7 +95,10 @@ start(Module, SockMod, Socket, Opts) ->
|
||||
end.
|
||||
|
||||
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} ->
|
||||
Receiver = ejabberd_receiver:start(Socket, gen_tcp, none),
|
||||
SocketData = #socket_state{sockmod = gen_tcp,
|
||||
|
@ -775,132 +775,66 @@ item_to_raw(#listitem{type = Type,
|
||||
SMatchMessage = if MatchMessage -> "1"; true -> "0" end,
|
||||
SMatchPresenceIn = if MatchPresenceIn -> "1"; true -> "0" end,
|
||||
SMatchPresenceOut = if MatchPresenceOut -> "1"; true -> "0" end,
|
||||
["'", SType, "', "
|
||||
"'", SValue, "', "
|
||||
"'", SAction, "', "
|
||||
"'", SOrder, "', "
|
||||
"'", SMatchAll, "', "
|
||||
"'", SMatchIQ, "', "
|
||||
"'", SMatchMessage, "', "
|
||||
"'", SMatchPresenceIn, "', "
|
||||
"'", SMatchPresenceOut, "'"].
|
||||
|
||||
[SType, SValue, SAction, SOrder, SMatchAll, SMatchIQ,
|
||||
SMatchMessage, SMatchPresenceIn, SMatchPresenceOut].
|
||||
|
||||
sql_get_default_privacy_list(LUser, LServer) ->
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
["select name from privacy_default_list "
|
||||
"where username='", Username, "';"]).
|
||||
odbc_queries:get_default_privacy_list(LServer, Username).
|
||||
|
||||
sql_get_default_privacy_list_t(LUser) ->
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["select name from privacy_default_list "
|
||||
"where username='", Username, "';"]).
|
||||
odbc_queries:get_default_privacy_list_t(Username).
|
||||
|
||||
sql_get_privacy_list_names(LUser, LServer) ->
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
["select name from privacy_list "
|
||||
"where username='", Username, "';"]).
|
||||
odbc_queries:get_privacy_list_names(LServer, Username).
|
||||
|
||||
sql_get_privacy_list_names_t(LUser) ->
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["select name from privacy_list "
|
||||
"where username='", Username, "';"]).
|
||||
odbc_queries:get_privacy_list_names_t(Username).
|
||||
|
||||
sql_get_privacy_list_id(LUser, LServer, Name) ->
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
SName = ejabberd_odbc:escape(Name),
|
||||
ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
["select id from privacy_list "
|
||||
"where username='", Username, "' and name='", SName, "';"]).
|
||||
odbc_queries:get_privacy_list_id(LServer, Username, SName).
|
||||
|
||||
sql_get_privacy_list_id_t(LUser, Name) ->
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
SName = ejabberd_odbc:escape(Name),
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["select id from privacy_list "
|
||||
"where username='", Username, "' and name='", SName, "';"]).
|
||||
odbc_queries:get_privacy_list_id_t(Username, SName).
|
||||
|
||||
sql_get_privacy_list_data(LUser, LServer, Name) ->
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
SName = ejabberd_odbc:escape(Name),
|
||||
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;"]).
|
||||
odbc_queries:get_privacy_list_data(LServer, Username, SName).
|
||||
|
||||
sql_get_privacy_list_data_by_id(ID, LServer) ->
|
||||
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;"]).
|
||||
odbc_queries:get_privacy_list_data_by_id(LServer, ID).
|
||||
|
||||
sql_set_default_privacy_list(LUser, Name) ->
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
SName = ejabberd_odbc:escape(Name),
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["delete from privacy_default_list "
|
||||
" where username='", Username, "';"]),
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["insert into privacy_default_list(username, name) "
|
||||
"values ('", Username, "', '", SName, "');"]).
|
||||
odbc_queries:set_default_privacy_list(Username, SName).
|
||||
|
||||
sql_unset_default_privacy_list(LUser, LServer) ->
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
["delete from privacy_default_list "
|
||||
" where username='", Username, "';"]).
|
||||
odbc_queries:unset_default_privacy_list(LServer, Username).
|
||||
|
||||
sql_remove_privacy_list(LUser, Name) ->
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
SName = ejabberd_odbc:escape(Name),
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["delete from privacy_list "
|
||||
"where username='", Username, "' and name='", SName, "';"]).
|
||||
odbc_queries:remove_privacy_list(Username, SName).
|
||||
|
||||
sql_add_privacy_list(LUser, Name) ->
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
SName = ejabberd_odbc:escape(Name),
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["insert into privacy_list(username, name) "
|
||||
"values ('", Username, "', '", SName, "');"]).
|
||||
odbc_queries:add_privacy_list(Username, SName).
|
||||
|
||||
sql_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, "', ", Items, ");"])
|
||||
end, RItems).
|
||||
odbc_queries:set_privacy_list(ID, RItems).
|
||||
|
||||
sql_del_privacy_lists(LUser, LServer) ->
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
Server = ejabberd_odbc:escape(LServer),
|
||||
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, "';"]).
|
||||
odbc_queries:del_privacy_lists(LServer, Server, Username).
|
||||
|
@ -640,18 +640,13 @@ remove_user(User, Server) when is_binary(User), is_binary(Server) ->
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
set_items(User, Server, #xmlel{children = Els}) ->
|
||||
try
|
||||
LUser = exmpp_stringprep:nodeprep(User),
|
||||
LServer = exmpp_stringprep:nameprep(Server),
|
||||
catch odbc_queries:sql_transaction(
|
||||
LServer,
|
||||
lists:flatmap(fun(El) ->
|
||||
process_item_set_t(LUser, LServer, El)
|
||||
end, Els))
|
||||
catch
|
||||
_ ->
|
||||
ok
|
||||
end.
|
||||
end, Els)).
|
||||
|
||||
process_item_set_t(LUser, LServer, #xmlel{} = El) ->
|
||||
try
|
||||
@ -868,13 +863,7 @@ record_to_string(#roster{us = {User, _Server},
|
||||
none -> "N"
|
||||
end,
|
||||
SAskMessage = ejabberd_odbc:escape(binary_to_list(AskMessage)),
|
||||
["'", Username, "',"
|
||||
"'", SJID, "',"
|
||||
"'", Nick, "',"
|
||||
"'", SSubscription, "',"
|
||||
"'", SAsk, "',"
|
||||
"'", SAskMessage, "',"
|
||||
"'N', '', 'item'"].
|
||||
[Username, SJID, Nick, SSubscription, SAsk, SAskMessage, "N", "", "item"].
|
||||
|
||||
groups_to_string(#roster{us = {User, _Server},
|
||||
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
|
||||
%% the database
|
||||
lists:foldl(fun([], Acc) -> Acc;
|
||||
lists:foldl(
|
||||
fun([], Acc) -> Acc;
|
||||
(Group, Acc) ->
|
||||
String = ["'", Username, "',"
|
||||
"'", SJID, "',"
|
||||
"'", ejabberd_odbc:escape(binary_to_list(Group)), "'"],
|
||||
[String|Acc] end, [], Groups).
|
||||
G = ejabberd_odbc:escape(binary_to_list(Group)),
|
||||
[[Username, SJID, G]|Acc] end, [], Groups).
|
||||
|
||||
webadmin_page(_, Host,
|
||||
#request{us = _US,
|
||||
|
@ -55,6 +55,8 @@
|
||||
-define(PGSQL_PORT, 5432).
|
||||
-define(MYSQL_PORT, 3306).
|
||||
|
||||
-define(TRANSACTION_TIMEOUT, 60000).
|
||||
-define(KEEPALIVE_TIMEOUT, 60000).
|
||||
-define(KEEPALIVE_QUERY, "SELECT 1;").
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
@ -68,7 +70,7 @@ start_link(Host, StartInterval) ->
|
||||
|
||||
sql_query(Host, Query) ->
|
||||
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
|
||||
%% 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(Host, F) ->
|
||||
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:
|
||||
sql_query_t(Query) ->
|
||||
@ -93,12 +95,12 @@ sql_query_t(Query) ->
|
||||
{error, "No SQL-driver information available."} ->
|
||||
% workaround for odbc bug
|
||||
{updated, 0};
|
||||
{error, _} ->
|
||||
throw(aborted);
|
||||
{error, Reason} ->
|
||||
throw({aborted, Reason});
|
||||
Rs when is_list(Rs) ->
|
||||
case lists:keymember(error, 1, Rs) of
|
||||
true ->
|
||||
throw(aborted);
|
||||
case lists:keysearch(error, 1, Rs) of
|
||||
{value, {error, Reason}} ->
|
||||
throw({aborted, Reason});
|
||||
_ ->
|
||||
QRes
|
||||
end;
|
||||
@ -177,7 +179,7 @@ handle_call({sql_query, Query}, _From, State) ->
|
||||
{reply, Reply, State}
|
||||
end;
|
||||
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, "query timed out"} ->
|
||||
{stop, timeout, State};
|
||||
@ -247,14 +249,22 @@ sql_query_internal(State, Query) ->
|
||||
mysql_to_odbc(mysql_conn:fetch(State#state.db_ref, Query, self()))
|
||||
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};
|
||||
execute_transaction(State, F, NRestarts) ->
|
||||
execute_transaction(State, F, NRestarts, _Reason) ->
|
||||
put(?STATE_KEY, State),
|
||||
sql_query_internal(State, "begin;"),
|
||||
case catch F() of
|
||||
aborted ->
|
||||
execute_transaction(State, F, NRestarts - 1);
|
||||
{aborted, Reason} ->
|
||||
execute_transaction(State, F, NRestarts - 1, Reason);
|
||||
{'EXIT', Reason} ->
|
||||
sql_query_internal(State, "rollback;"),
|
||||
{aborted, Reason};
|
||||
@ -330,11 +340,6 @@ mysql_connect(Server, Port, DB, Username, Password, StartInterval) ->
|
||||
{ok, Ref} ->
|
||||
erlang:monitor(process, Ref),
|
||||
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}};
|
||||
{error, Reason} ->
|
||||
?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.
|
||||
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(Level, Format, Args) ->
|
||||
|
@ -61,6 +61,20 @@
|
||||
set_private_data_sql/3,
|
||||
get_private_data/3,
|
||||
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,
|
||||
get_vcard/2,
|
||||
escape/1,
|
||||
@ -74,6 +88,14 @@
|
||||
-define(generic, true).
|
||||
-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
|
||||
-ifdef(generic).
|
||||
@ -81,9 +103,25 @@
|
||||
get_db_type() ->
|
||||
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
|
||||
%% TODO: We should probably move the list of queries transaction wrapper from the ejabberd_odbc module
|
||||
%% to this one (odbc_queries)
|
||||
%% TODO: We should probably move the list of queries transaction
|
||||
%% wrapper from the ejabberd_odbc module to this one (odbc_queries)
|
||||
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
|
||||
ejabberd_odbc:sql_transaction(
|
||||
LServer,
|
||||
[["delete from last where username='", Username, "';"],
|
||||
["insert into last(username, seconds, state) "
|
||||
"values ('", Username, "', '", Seconds, "', '", State, "');"]]).
|
||||
fun() ->
|
||||
update_t("last", ["username", "seconds", "state"],
|
||||
[Username, Seconds, State],
|
||||
["username='", Username, "'"])
|
||||
end).
|
||||
|
||||
del_last(LServer, Username) ->
|
||||
ejabberd_odbc:sql_query(
|
||||
@ -115,9 +155,11 @@ get_password(LServer, Username) ->
|
||||
set_password_t(LServer, Username, Pass) ->
|
||||
ejabberd_odbc:sql_transaction(
|
||||
LServer,
|
||||
[["delete from users where username='", Username ,"';"],
|
||||
["insert into users(username, password) "
|
||||
"values ('", Username, "', '", Pass, "');"]]).
|
||||
fun() ->
|
||||
update_t("users", ["username", "password"],
|
||||
[Username, Pass],
|
||||
["username='", Username ,"'"])
|
||||
end).
|
||||
|
||||
add_user(LServer, Username, Pass) ->
|
||||
ejabberd_odbc:sql_query(
|
||||
@ -296,16 +338,11 @@ del_roster_sql(Username, SJID) ->
|
||||
" and jid='", SJID, "';"]].
|
||||
|
||||
update_roster(_LServer, Username, SJID, ItemVals, ItemGroups) ->
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["delete from rosterusers "
|
||||
" where username='", Username, "' "
|
||||
" and jid='", SJID, "';"]),
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["insert into rosterusers("
|
||||
" username, jid, nick, "
|
||||
" subscription, ask, askmessage, "
|
||||
" server, subscribe, type) "
|
||||
" values (", ItemVals, ");"]),
|
||||
update_t("rosterusers",
|
||||
["username", "jid", "nick", "subscription", "ask",
|
||||
"askmessage", "server", "subscribe", "type"],
|
||||
ItemVals,
|
||||
["username='", Username, "' and jid='", SJID, "'"]),
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["delete from rostergroups "
|
||||
" where username='", Username, "' "
|
||||
@ -314,7 +351,7 @@ update_roster(_LServer, Username, SJID, ItemVals, ItemGroups) ->
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["insert into rostergroups("
|
||||
" username, jid, grp) "
|
||||
" values (", ItemGroup, ");"])
|
||||
" values ('", join(ItemGroup, "', '"), "');"])
|
||||
end,
|
||||
ItemGroups).
|
||||
|
||||
@ -326,26 +363,21 @@ update_roster_sql(Username, SJID, ItemVals, ItemGroups) ->
|
||||
" username, jid, nick, "
|
||||
" subscription, ask, askmessage, "
|
||||
" server, subscribe, type) "
|
||||
" values (", ItemVals, ");"],
|
||||
" values ('", join(ItemVals, "', '"), "');"],
|
||||
["delete from rostergroups "
|
||||
" where username='", Username, "' "
|
||||
" and jid='", SJID, "';"]] ++
|
||||
[["insert into rostergroups("
|
||||
" username, jid, grp) "
|
||||
" values (", ItemGroup, ");"] ||
|
||||
" values ('", join(ItemGroup, "', '"), "');"] ||
|
||||
ItemGroup <- ItemGroups].
|
||||
|
||||
roster_subscribe(_LServer, Username, SJID, ItemVals) ->
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["delete from rosterusers "
|
||||
" where username='", Username, "' "
|
||||
" and jid='", SJID, "';"]),
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["insert into rosterusers("
|
||||
" username, jid, nick, "
|
||||
" subscription, ask, askmessage, "
|
||||
" server, subscribe, type) "
|
||||
" values (", ItemVals, ");"]).
|
||||
update_t("rosterusers",
|
||||
["username", "jid", "nick", "subscription", "ask",
|
||||
"askmessage", "server", "subscribe", "type"],
|
||||
ItemVals,
|
||||
["username='", Username, "' and jid='", SJID, "'"]).
|
||||
|
||||
get_subscription(LServer, Username, SJID) ->
|
||||
ejabberd_odbc:sql_query(
|
||||
@ -355,10 +387,10 @@ get_subscription(LServer, Username, SJID) ->
|
||||
"and jid='", SJID, "'"]).
|
||||
|
||||
set_private_data(_LServer, Username, LXMLNS, SData) ->
|
||||
lists:foreach(fun(Query) ->
|
||||
ejabberd_odbc:sql_query_t(Query)
|
||||
end,
|
||||
set_private_data_sql(Username, LXMLNS, SData)).
|
||||
update_t("private_storage",
|
||||
["username", "namespace", "data"],
|
||||
[Username, LXMLNS, SData],
|
||||
["username='", Username, "' and namespace='", LXMLNS, "'"]).
|
||||
|
||||
set_private_data_sql(Username, LXMLNS, SData) ->
|
||||
[["delete from private_storage "
|
||||
@ -380,35 +412,29 @@ del_user_private_storage(LServer, Username) ->
|
||||
LServer,
|
||||
["delete from private_storage where username='", Username, "';"]).
|
||||
|
||||
|
||||
set_vcard(LServer, LUsername, SBDay, SCTRY, SEMail, SFN, SFamily, SGiven,
|
||||
SLBDay, SLCTRY, SLEMail, SLFN, SLFamily, SLGiven, SLLocality,
|
||||
SLMiddle, SLNickname, SLOrgName, SLOrgUnit, SLocality, SMiddle,
|
||||
SNickname, SOrgName, SOrgUnit, SVCARD, Username) ->
|
||||
ejabberd_odbc:sql_transaction(
|
||||
LServer,
|
||||
[["delete from vcard where username='", LUsername, "';"],
|
||||
["insert into vcard(username, vcard) "
|
||||
"values ('", LUsername, "', '", SVCARD, "');"],
|
||||
["delete from vcard_search where lusername='", LUsername, "';"],
|
||||
["insert into vcard_search("
|
||||
" username, lusername, fn, lfn, family, lfamily,"
|
||||
" given, lgiven, middle, lmiddle, nickname, lnickname,"
|
||||
" bday, lbday, ctry, lctry, locality, llocality,"
|
||||
" email, lemail, orgname, lorgname, orgunit, lorgunit)"
|
||||
"values (",
|
||||
" '", Username, "', '", LUsername, "',"
|
||||
" '", SFN, "', '", SLFN, "',"
|
||||
" '", SFamily, "', '", SLFamily, "',"
|
||||
" '", SGiven, "', '", SLGiven, "',"
|
||||
" '", SMiddle, "', '", SLMiddle, "',"
|
||||
" '", SNickname, "', '", SLNickname, "',"
|
||||
" '", SBDay, "', '", SLBDay, "',"
|
||||
" '", SCTRY, "', '", SLCTRY, "',"
|
||||
" '", SLocality, "', '", SLLocality, "',"
|
||||
" '", SEMail, "', '", SLEMail, "',"
|
||||
" '", SOrgName, "', '", SLOrgName, "',"
|
||||
" '", SOrgUnit, "', '", SLOrgUnit, "');"]]).
|
||||
fun() ->
|
||||
update_t("vcard", ["username", "vcard"],
|
||||
[LUsername, SVCARD],
|
||||
["username='", LUsername, "'"]),
|
||||
update_t("vcard_search",
|
||||
["username", "lusername", "fn", "lfn", "family",
|
||||
"lfamily", "given", "lgiven", "middle", "lmiddle",
|
||||
"nickname", "lnickname", "bday", "lbday", "ctry",
|
||||
"lctry", "locality", "llocality", "email", "lemail",
|
||||
"orgname", "lorgname", "orgunit", "lorgunit"],
|
||||
[Username, LUsername, SFN, SLFN, SFamily, SLFamily,
|
||||
SGiven, SLGiven, SMiddle, SLMiddle, SNickname,
|
||||
SLNickname, SBDay, SLBDay, SCTRY, SLCTRY,
|
||||
SLocality, SLLocality, SEMail, SLEMail, SOrgName,
|
||||
SLOrgName, SOrgUnit, SLOrgUnit],
|
||||
["lusername='", LUsername, "'"])
|
||||
end).
|
||||
|
||||
get_vcard(LServer, Username) ->
|
||||
ejabberd_odbc:sql_query(
|
||||
@ -416,6 +442,103 @@ get_vcard(LServer, Username) ->
|
||||
["select vcard from vcard "
|
||||
"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
|
||||
escape($\0) -> "\\0";
|
||||
escape($\n) -> "\\n";
|
||||
|
@ -1447,15 +1447,24 @@ user_info(User, Server, Query, Lang) ->
|
||||
_ ->
|
||||
[?XE('ul',
|
||||
lists:map(fun(R) ->
|
||||
FIP = case ejabberd_sm:get_user_ip(
|
||||
FIP = case ejabberd_sm:get_user_info(
|
||||
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) ++
|
||||
":" ++
|
||||
integer_to_list(Port)
|
||||
++ "#" ++ atom_to_list(Node)
|
||||
++ ")"
|
||||
end,
|
||||
?LI([?C(R ++ FIP)])
|
||||
|
Loading…
Reference in New Issue
Block a user