25
1
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:
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>
* 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)

View File

@ -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, &lt;resource&gt;}</TT></B></DT><DD CLASS="dd-description"> Matches any JID with a resource
<TT>&lt;resource&gt;</TT>. Example:
<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
matches <TT>&lt;regexp&gt;</TT> on local virtual hosts. Example:
<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.
\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
View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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