24
1
mirror of https://github.com/processone/ejabberd.git synced 2024-09-29 14:37:44 +02: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:
Jean-Sébastien Pédron 2009-01-19 11:16:44 +00:00
parent 8a27b5446d
commit bc51bd0dbd
16 changed files with 1074 additions and 855 deletions

View File

@ -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)

View File

@ -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, &lt;resource&gt;}</TT></B></DT><DD CLASS="dd-description"> Matches any JID with a resource </PRE></DD><DT CLASS="dt-description"><B><TT>{resource, &lt;resource&gt;}</TT></B></DT><DD CLASS="dd-description"> Matches any JID with a resource
<TT>&lt;resource&gt;</TT>. Example: <TT>&lt;resource&gt;</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, &lt;groupname&gt;}</TT></B></DT><DD CLASS="dd-description"> Matches any member of a Shared Roster Group with name <TT>&lt;groupname&gt;</TT> in the virtual host. Example:
<PRE CLASS="verbatim">{acl, techgroupmembers, {shared_group, "techteam"}}.
</PRE></DD><DT CLASS="dt-description"><B><TT>{shared_group, &lt;groupname&gt;, &lt;server&gt;}</TT></B></DT><DD CLASS="dd-description"> Matches any member of a Shared Roster Group with name <TT>&lt;groupname&gt;</TT> in the virtual host <TT>&lt;server&gt;</TT>. Example:
<PRE CLASS="verbatim">{acl, techgroupmembers, {shared_group, "techteam", "example.org"}}.
</PRE></DD><DT CLASS="dt-description"><B><TT>{user_regexp, &lt;regexp&gt;}</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, &lt;regexp&gt;}</TT></B></DT><DD CLASS="dd-description"> Matches any local user with a name that
matches <TT>&lt;regexp&gt;</TT> on local virtual hosts. Example: matches <TT>&lt;regexp&gt;</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]*$"}}.

View File

@ -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
View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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)])],

View File

@ -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

View File

@ -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
undefined ->
%% Matching JID: The stanza is ok
case exmpp_jid:compare_bare_jids(JIDEl, FromJID) of
true -> true ->
El; El;
false -> false ->
'invalid-from' '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
_:_ -> _:_ ->

View File

@ -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} ->

View File

@ -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,
%% 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}, [binary, {packet, 0},
{active, false}]) of {active, false}, Type],
Timeout)) of
{ok, _Socket} = R -> R; {ok, _Socket} = R -> R;
{error, Reason1} -> {error, Reason} = R ->
?DEBUG("s2s_out: connect return ~p~n", [Reason1]), ?DEBUG("s2s_out: connect return ~p~n", [Reason]),
catch ejabberd_socket:connect( R;
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};
{'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;

View File

@ -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,

View File

@ -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, "';"]).

View File

@ -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(
fun([], Acc) -> Acc;
(Group, Acc) -> (Group, Acc) ->
String = ["'", Username, "'," G = ejabberd_odbc:escape(binary_to_list(Group)),
"'", SJID, "'," [[Username, SJID, G]|Acc] end, [], Groups).
"'", ejabberd_odbc:escape(binary_to_list(Group)), "'"],
[String|Acc] end, [], Groups).
webadmin_page(_, Host, webadmin_page(_, Host,
#request{us = _US, #request{us = _US,

View File

@ -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) ->

View File

@ -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";

View File

@ -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)])