mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-22 16:20:52 +01:00
Patch core for MH (thanks to Alexey Shchepin and Geoff Cant)
This commit is contained in:
parent
9336356efd
commit
cdb379a22c
20
src/acl.erl
20
src/acl.erl
@ -32,10 +32,12 @@
|
||||
add/3,
|
||||
add_list/3,
|
||||
match_rule/3,
|
||||
for_host/1,
|
||||
% for debugging only
|
||||
match_acl/3]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include_lib("stdlib/include/ms_transform.hrl").
|
||||
|
||||
%% @type aclspec() = all | JID_Exact | JID_Regexp | JID_Glob | Shared_Group
|
||||
%% JID_Exact = {user, U} | {user, U, S} | {server, S} | {resource, R}
|
||||
@ -234,7 +236,7 @@ match_acl(ACLName, JID, Host) ->
|
||||
User = exmpp_jid:prep_node_as_list(JID),
|
||||
Server = exmpp_jid:prep_domain_as_list(JID),
|
||||
Resource = exmpp_jid:prep_resource_as_list(JID),
|
||||
lists:any(fun(#acl{aclspec = Spec}) ->
|
||||
lists:any(fun(#acl{aclname=Name, aclspec = Spec}) ->
|
||||
case Spec of
|
||||
all ->
|
||||
true;
|
||||
@ -243,17 +245,21 @@ match_acl(ACLName, JID, Host) ->
|
||||
andalso
|
||||
((Host == Server) orelse
|
||||
((Host == global) andalso
|
||||
lists:member(Server, ?MYHOSTS)));
|
||||
?IS_MY_HOST(Server)));
|
||||
{user, U, S} ->
|
||||
(U == User) andalso (S == Server);
|
||||
{server, S} ->
|
||||
S == Server;
|
||||
{resource, R} ->
|
||||
R == Resource;
|
||||
{user_regexp, UR} when is_tuple(Name),
|
||||
element(2, Name) =:= global ->
|
||||
?IS_MY_HOST(Server)
|
||||
andalso is_regexp_match(User, UR);
|
||||
{user_regexp, UR} ->
|
||||
((Host == Server) orelse
|
||||
((Host == global) andalso
|
||||
lists:member(Server, ?MYHOSTS)))
|
||||
?IS_MY_HOST(Server)))
|
||||
andalso is_regexp_match(User, UR);
|
||||
{shared_group, G} ->
|
||||
mod_shared_roster:is_user_in_group({User, Server}, G, Host);
|
||||
@ -272,7 +278,7 @@ match_acl(ACLName, JID, Host) ->
|
||||
{user_glob, UR} ->
|
||||
((Host == Server) orelse
|
||||
((Host == global) andalso
|
||||
lists:member(Server, ?MYHOSTS)))
|
||||
?IS_MY_HOST(Server)))
|
||||
andalso
|
||||
is_glob_match(User, UR);
|
||||
{user_glob, UR, S} ->
|
||||
@ -325,3 +331,9 @@ is_glob_match(String, Glob) ->
|
||||
is_regexp_match(String, xmerl_regexp:sh_to_awk(Glob)).
|
||||
|
||||
|
||||
for_host(Host) ->
|
||||
mnesia:select(acl,
|
||||
ets:fun2ms(fun (#acl{aclname = {_ACLName, H}})
|
||||
when H =:= Host ->
|
||||
object()
|
||||
end)).
|
||||
|
@ -28,8 +28,14 @@
|
||||
-author('alexey@process-one.net').
|
||||
|
||||
-export([start/0, stop/0,
|
||||
get_pid_file/0,
|
||||
get_so_path/0, get_bin_path/0]).
|
||||
get_so_path/0,
|
||||
get_bin_path/0,
|
||||
get_pid_file/0,
|
||||
is_my_host/1,
|
||||
normalize_host/1
|
||||
]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
|
||||
start() ->
|
||||
%%ejabberd_cover:start(),
|
||||
@ -65,6 +71,33 @@ get_bin_path() ->
|
||||
Path
|
||||
end.
|
||||
|
||||
is_my_host([$* | _]) ->
|
||||
false;
|
||||
is_my_host(Host) ->
|
||||
case ejabberd_config:get_local_option({Host, host}) of
|
||||
undefined ->
|
||||
WCHost = re:replace(Host, "^[^.]*\.", "*.", [{return, list}]),
|
||||
case ejabberd_config:get_local_option({WCHost, host}) of
|
||||
undefined ->
|
||||
false;
|
||||
_ ->
|
||||
true
|
||||
end;
|
||||
_ ->
|
||||
true
|
||||
end.
|
||||
|
||||
normalize_host(global) ->
|
||||
global;
|
||||
normalize_host(Host) ->
|
||||
WCHost = re:replace(Host, "^[^.]*\.", "*.", [{return, list}]),
|
||||
case ejabberd_config:get_local_option({WCHost, host}) of
|
||||
undefined ->
|
||||
Host;
|
||||
_ ->
|
||||
WCHost
|
||||
end.
|
||||
|
||||
%% @spec () -> false | string()
|
||||
get_pid_file() ->
|
||||
case os:getenv("EJABBERD_PID_PATH") of
|
||||
|
@ -23,7 +23,8 @@
|
||||
%% If the ejabberd application description isn't loaded, returns atom: undefined
|
||||
-define(VERSION, element(2, application:get_key(ejabberd,vsn))).
|
||||
|
||||
-define(MYHOSTS, ejabberd_config:get_global_option(hosts)).
|
||||
-define(IS_MY_HOST(Host), ejabberd:is_my_host(Host)).
|
||||
-define(MYHOSTS, ejabberd_config:get_global_option(hosts)). %% Deprecated
|
||||
-define(MYNAME, hd(ejabberd_config:get_global_option(hosts))).
|
||||
-define(MYLANG, ejabberd_config:get_global_option(language)).
|
||||
|
||||
@ -35,6 +36,8 @@
|
||||
|
||||
-define(S2STIMEOUT, 600000).
|
||||
|
||||
-define(PRIVACY_SUPPORT, true).
|
||||
|
||||
%%-define(DBGFSM, true).
|
||||
|
||||
%% ---------------------------------
|
||||
@ -58,4 +61,3 @@
|
||||
|
||||
-define(CRITICAL_MSG(Format, Args),
|
||||
ejabberd_logger:critical_msg(?MODULE,?LINE,Format, Args)).
|
||||
|
||||
|
@ -278,8 +278,8 @@ send_service_message_all_mucs(Subject, AnnouncementText) ->
|
||||
Message = io_lib:format("~s~n~s", [Subject, AnnouncementText]),
|
||||
lists:foreach(
|
||||
fun(ServerHost) ->
|
||||
MUCHost = gen_mod:get_module_opt_host(
|
||||
ServerHost, mod_muc, "conference.@HOST@"),
|
||||
MUCHost = gen_mod:expand_host_name(
|
||||
ServerHost, mod_muc, "conference"),
|
||||
MUCHostB = list_to_binary(MUCHost),
|
||||
mod_muc:broadcast_service_message(MUCHostB, Message)
|
||||
end,
|
||||
|
@ -119,6 +119,15 @@ db_init() ->
|
||||
|
||||
%% Start all the modules in all the hosts
|
||||
start_modules() ->
|
||||
case ejabberd_config:get_local_option({static_modules, global}) of
|
||||
undefined ->
|
||||
ok;
|
||||
StaticModules ->
|
||||
lists:foreach(
|
||||
fun({Module, Args}) ->
|
||||
gen_mod:start_module(global, Module, Args)
|
||||
end, StaticModules)
|
||||
end,
|
||||
lists:foreach(
|
||||
fun(Host) ->
|
||||
case ejabberd_config:get_local_option({modules, Host}) of
|
||||
|
@ -52,6 +52,15 @@
|
||||
plain_password_required/1
|
||||
]).
|
||||
|
||||
-export([start/1
|
||||
,start_module/2
|
||||
,stop_module/2
|
||||
,start_modules/2
|
||||
,start_method/2
|
||||
,stop_method/2
|
||||
,start_methods/2
|
||||
]).
|
||||
|
||||
-export([auth_modules/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
@ -67,13 +76,26 @@
|
||||
%% @spec () -> term()
|
||||
|
||||
start() ->
|
||||
lists:foreach(
|
||||
fun(Host) ->
|
||||
lists:foreach(
|
||||
fun(M) ->
|
||||
M:start(Host)
|
||||
end, auth_modules(Host))
|
||||
end, ?MYHOSTS).
|
||||
?DEBUG("About to start auth modules. Hosts: ~p", ?MYHOSTS),
|
||||
lists:foreach(fun start/1, ?MYHOSTS).
|
||||
|
||||
start(Host) ->
|
||||
start_modules(Host, auth_modules(Host)).
|
||||
|
||||
start_modules(Host, Modules) when is_list(Modules) ->
|
||||
lists:foreach(fun (M) -> start_module(Host, M) end, Modules).
|
||||
start_module(Host, Module) when is_atom(Module) ->
|
||||
Module:start(Host).
|
||||
stop_module(Host, Module) when is_atom(Module) ->
|
||||
Module:stop(Host).
|
||||
|
||||
start_methods(Host, Methods) when is_list(Methods) ->
|
||||
lists:foreach(fun (M) -> start_method(Host, M) end, Methods).
|
||||
start_method(Host, Method) when is_atom(Method) ->
|
||||
start_module(Host, module_name(Method)).
|
||||
stop_method(Host, Method) when is_atom(Method) ->
|
||||
stop_module(Host, module_name(Method)).
|
||||
|
||||
|
||||
%% @spec (Server) -> bool()
|
||||
%% Server = string()
|
||||
@ -186,7 +208,7 @@ try_register(User, Server, Password)
|
||||
true ->
|
||||
{atomic, exists};
|
||||
false ->
|
||||
case lists:member(exmpp_stringprep:nameprep(Server), ?MYHOSTS) of
|
||||
case ?IS_MY_HOST(exmpp_stringprep:nameprep(Server)) of
|
||||
true ->
|
||||
Res = lists:foldl(
|
||||
fun (_M, {atomic, ok} = Res) ->
|
||||
@ -443,10 +465,13 @@ auth_modules() ->
|
||||
|
||||
auth_modules(Server) when is_list(Server) ->
|
||||
LServer = exmpp_stringprep:nameprep(Server),
|
||||
Method = ejabberd_config:get_local_option({auth_method, LServer}),
|
||||
Method = ejabberd_config:get_local_option({auth_method, ejabberd:normalize_host(LServer)}),
|
||||
Methods = if
|
||||
Method == undefined -> [];
|
||||
is_list(Method) -> Method;
|
||||
is_atom(Method) -> [Method]
|
||||
end,
|
||||
[list_to_atom("ejabberd_auth_" ++ atom_to_list(M)) || M <- Methods].
|
||||
[module_name(M) || M <- Methods].
|
||||
|
||||
module_name(Method) when is_atom(Method) ->
|
||||
list_to_atom("ejabberd_auth_" ++ atom_to_list(Method)).
|
||||
|
@ -72,7 +72,6 @@
|
||||
base,
|
||||
uids,
|
||||
ufilter,
|
||||
sfilter,
|
||||
lfilter, %% Local filter (performed by ejabberd, not LDAP)
|
||||
dn_filter,
|
||||
dn_filter_attrs
|
||||
@ -99,21 +98,41 @@ handle_info(_Info, State) ->
|
||||
%% Host = string()
|
||||
|
||||
start(Host) ->
|
||||
Proc = gen_mod:get_module_proc(Host, ?MODULE),
|
||||
ChildSpec = {
|
||||
Proc, {?MODULE, start_link, [Host]},
|
||||
transient, 1000, worker, [?MODULE]
|
||||
},
|
||||
supervisor:start_child(ejabberd_sup, ChildSpec).
|
||||
?DEBUG("Starting ~p for ~p.", [?MODULE, Host]),
|
||||
case ejabberd_config:get_host_option(Host, ldap_servers) of
|
||||
undefined -> check_bad_config(Host);
|
||||
{host, _Host} -> ok;
|
||||
_ ->
|
||||
Proc = gen_mod:get_module_proc(Host, ?MODULE),
|
||||
ChildSpec = {
|
||||
Proc, {?MODULE, start_link, [Host]},
|
||||
transient, 1000, worker, [?MODULE]
|
||||
},
|
||||
supervisor:start_child(ejabberd_sup, ChildSpec)
|
||||
end.
|
||||
|
||||
check_bad_config(Host) ->
|
||||
case ejabberd_config:get_local_option({ldap_servers, Host}) of
|
||||
undefined ->
|
||||
?ERROR_MSG("Can't start ~p for host ~p: missing ldap_servers configuration",
|
||||
[?MODULE, Host]),
|
||||
{error, bad_config};
|
||||
_ -> ok
|
||||
end.
|
||||
|
||||
%% @spec (Host) -> term()
|
||||
%% Host = string()
|
||||
|
||||
stop(Host) ->
|
||||
Proc = gen_mod:get_module_proc(Host, ?MODULE),
|
||||
gen_server:call(Proc, stop),
|
||||
supervisor:terminate_child(ejabberd_sup, Proc),
|
||||
supervisor:delete_child(ejabberd_sup, Proc).
|
||||
case ejabberd_config:get_host_option(Host, ldap_servers) of
|
||||
undefined -> ok;
|
||||
{host, _Host} -> ok;
|
||||
_ ->
|
||||
Proc = gen_mod:get_module_proc(Host, ?MODULE),
|
||||
gen_server:call(Proc, stop),
|
||||
supervisor:terminate_child(ejabberd_sup, Proc),
|
||||
supervisor:delete_child(ejabberd_sup, Proc)
|
||||
end.
|
||||
|
||||
%% @spec (Host) -> term()
|
||||
%% Host = string()
|
||||
@ -190,7 +209,7 @@ check_password(User, Server, Password, _Digest, _DigestGen) ->
|
||||
|
||||
set_password(User, Server, Password) ->
|
||||
{ok, State} = eldap_utils:get_state(Server, ?MODULE),
|
||||
case find_user_dn(User, State) of
|
||||
case find_user_dn(User, Server, State) of
|
||||
false ->
|
||||
{error, user_not_found};
|
||||
DN ->
|
||||
@ -285,8 +304,8 @@ remove_user(_User, _Server, _Password) ->
|
||||
%% Password = string()
|
||||
|
||||
check_password_ldap(User, Server, Password) ->
|
||||
{ok, State} = eldap_utils:get_state(Server, ?MODULE),
|
||||
case find_user_dn(User, State) of
|
||||
{ok, State} = get_state(Server),
|
||||
case find_user_dn(User, Server, State) of
|
||||
false ->
|
||||
false;
|
||||
DN ->
|
||||
@ -294,7 +313,21 @@ check_password_ldap(User, Server, Password) ->
|
||||
ok -> true;
|
||||
_ -> false
|
||||
end
|
||||
end.
|
||||
end.
|
||||
|
||||
%% We need an ?MODULE server state to use for queries. This will
|
||||
%% either be Server if this is a statically configured host or the
|
||||
%% Server for a different host if this is a dynamically configured
|
||||
%% vhost.
|
||||
%% The {ldap_vhost, Server} -> Host. ejabberd config option specifies
|
||||
%% which actual ?MODULE server to use for a particular Host. The value
|
||||
%% of the option if it is defined or Server by default.
|
||||
get_state(Server) ->
|
||||
Host = case ejabberd_config:get_local_option({ldap_servers, Server}) of
|
||||
{host, H} -> H;
|
||||
_ -> Server
|
||||
end,
|
||||
eldap_utils:get_state(Host, ?MODULE).
|
||||
|
||||
%% @spec (Server) -> [{LUser, LServer}]
|
||||
%% Server = string()
|
||||
@ -303,11 +336,11 @@ check_password_ldap(User, Server, Password) ->
|
||||
|
||||
get_vh_registered_users_ldap(Server) ->
|
||||
{ok, State} = eldap_utils:get_state(Server, ?MODULE),
|
||||
UIDs = State#state.uids,
|
||||
UIDs = eldap_utils:uids_domain_subst(Server, State#state.uids),
|
||||
Eldap_ID = State#state.eldap_id,
|
||||
Server = State#state.host,
|
||||
SearchFilter = build_sfilter(State, UIDs),
|
||||
ResAttrs = result_attrs(State),
|
||||
case eldap_filter:parse(State#state.sfilter) of
|
||||
case eldap_filter:parse(SearchFilter) of
|
||||
{ok, EldapFilter} ->
|
||||
case eldap_pool:search(Eldap_ID, [{base, State#state.base},
|
||||
{filter, EldapFilter},
|
||||
@ -317,7 +350,7 @@ get_vh_registered_users_ldap(Server) ->
|
||||
lists:flatmap(
|
||||
fun(#eldap_entry{attributes = Attrs,
|
||||
object_name = DN}) ->
|
||||
case is_valid_dn(DN, Attrs, State) of
|
||||
case is_valid_dn(DN, Server, Attrs, State) of
|
||||
false -> [];
|
||||
_ ->
|
||||
case eldap_utils:find_ldap_attrs(UIDs, Attrs) of
|
||||
@ -349,7 +382,7 @@ get_vh_registered_users_ldap(Server) ->
|
||||
|
||||
is_user_exists_ldap(User, Server) ->
|
||||
{ok, State} = eldap_utils:get_state(Server, ?MODULE),
|
||||
case find_user_dn(User, State) of
|
||||
case find_user_dn(User, Server, State) of
|
||||
false -> false;
|
||||
_DN -> true
|
||||
end.
|
||||
@ -363,16 +396,17 @@ handle_call(stop, _From, State) ->
|
||||
handle_call(_Request, _From, State) ->
|
||||
{reply, bad_request, State}.
|
||||
|
||||
find_user_dn(User, State) ->
|
||||
find_user_dn(User, Server, State) ->
|
||||
ResAttrs = result_attrs(State),
|
||||
case eldap_filter:parse(State#state.ufilter, [{"%u", User}]) of
|
||||
UserFilter = build_ufilter(State, Server),
|
||||
case eldap_filter:parse(UserFilter, [{"%u", User}]) of
|
||||
{ok, Filter} ->
|
||||
case eldap_pool:search(State#state.eldap_id, [{base, State#state.base},
|
||||
{filter, Filter},
|
||||
{attributes, ResAttrs}]) of
|
||||
#eldap_search_result{entries = [#eldap_entry{attributes = Attrs,
|
||||
object_name = DN} | _]} ->
|
||||
dn_filter(DN, Attrs, State);
|
||||
dn_filter(DN, Server, Attrs, State);
|
||||
_ ->
|
||||
false
|
||||
end;
|
||||
@ -381,20 +415,20 @@ find_user_dn(User, State) ->
|
||||
end.
|
||||
|
||||
%% apply the dn filter and the local filter:
|
||||
dn_filter(DN, Attrs, State) ->
|
||||
dn_filter(DN, Server, Attrs, State) ->
|
||||
%% Check if user is denied access by attribute value (local check)
|
||||
case check_local_filter(Attrs, State) of
|
||||
false -> false;
|
||||
true -> is_valid_dn(DN, Attrs, State)
|
||||
true -> is_valid_dn(DN, Server, Attrs, State)
|
||||
end.
|
||||
|
||||
%% Check that the DN is valid, based on the dn filter
|
||||
is_valid_dn(DN, _, #state{dn_filter = undefined}) ->
|
||||
is_valid_dn(DN, _, _, #state{dn_filter = undefined}) ->
|
||||
DN;
|
||||
|
||||
is_valid_dn(DN, Attrs, State) ->
|
||||
is_valid_dn(DN, Server, Attrs, State) ->
|
||||
DNAttrs = State#state.dn_filter_attrs,
|
||||
UIDs = State#state.uids,
|
||||
UIDs = eldap_utils:uids_domain_subst(Server, State#state.uids),
|
||||
Values = [{"%s", eldap_utils:get_ldap_attr(Attr, Attrs), 1} || Attr <- DNAttrs],
|
||||
SubstValues = case eldap_utils:find_ldap_attrs(UIDs, Attrs) of
|
||||
"" -> Values;
|
||||
@ -449,6 +483,22 @@ result_attrs(#state{uids = UIDs, dn_filter_attrs = DNFilterAttrs}) ->
|
||||
[UID | Acc]
|
||||
end, DNFilterAttrs, UIDs).
|
||||
|
||||
build_ufilter(State, VHost) ->
|
||||
UIDs = eldap_utils:uids_domain_subst(VHost, State#state.uids),
|
||||
SubFilter = lists:flatten(eldap_utils:generate_subfilter(UIDs)),
|
||||
case State#state.ufilter of
|
||||
"" -> SubFilter;
|
||||
F -> "(&" ++ SubFilter ++ F ++ ")"
|
||||
end.
|
||||
|
||||
build_sfilter(State, FormattedUIDs) ->
|
||||
SubFilter = lists:flatten(eldap_utils:generate_subfilter(FormattedUIDs)),
|
||||
UserFilter = case State#state.ufilter of
|
||||
"" -> SubFilter;
|
||||
F -> "(&" ++ SubFilter ++ F ++ ")"
|
||||
end,
|
||||
eldap_filter:do_sub(UserFilter, [{"%u", "*"}]).
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% Auxiliary functions
|
||||
%%%----------------------------------------------------------------------
|
||||
@ -480,15 +530,12 @@ parse_options(Host) ->
|
||||
end,
|
||||
UIDs = case ejabberd_config:get_local_option({ldap_uids, Host}) of
|
||||
undefined -> [{"uid", "%u"}];
|
||||
UI -> eldap_utils:uids_domain_subst(Host, UI)
|
||||
UI -> UI
|
||||
end,
|
||||
SubFilter = lists:flatten(eldap_utils:generate_subfilter(UIDs)),
|
||||
UserFilter = case ejabberd_config:get_local_option({ldap_filter, Host}) of
|
||||
undefined -> SubFilter;
|
||||
"" -> SubFilter;
|
||||
F -> "(&" ++ SubFilter ++ F ++ ")"
|
||||
undefined -> "";
|
||||
F -> F
|
||||
end,
|
||||
SearchFilter = eldap_filter:do_sub(UserFilter, [{"%u", "*"}]),
|
||||
LDAPBase = ejabberd_config:get_local_option({ldap_base, Host}),
|
||||
{DNFilter, DNFilterAttrs} =
|
||||
case ejabberd_config:get_local_option({ldap_dn_filter, Host}) of
|
||||
@ -513,7 +560,6 @@ parse_options(Host) ->
|
||||
base = LDAPBase,
|
||||
uids = UIDs,
|
||||
ufilter = UserFilter,
|
||||
sfilter = SearchFilter,
|
||||
lfilter = LocalFilter,
|
||||
dn_filter = DNFilter,
|
||||
dn_filter_attrs = DNFilterAttrs
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
%% External exports
|
||||
-export([start/1,
|
||||
stop/1,
|
||||
set_password/3,
|
||||
check_password/3,
|
||||
check_password/5,
|
||||
@ -55,8 +56,14 @@
|
||||
%% @spec (Host) -> ok
|
||||
%% Host = string()
|
||||
|
||||
start(_Host) ->
|
||||
ok.
|
||||
start(Host) ->
|
||||
case ejabberd_odbc:running(Host) of
|
||||
true -> ok;
|
||||
false -> ejabberd_rdbms:start_odbc(Host)
|
||||
end.
|
||||
|
||||
stop(Host) ->
|
||||
ejabberd_rdbms:stop_odbc(Host).
|
||||
|
||||
%% @spec () -> bool()
|
||||
|
||||
|
@ -315,7 +315,7 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) ->
|
||||
ServerB = exmpp_stringprep:nameprep(
|
||||
exmpp_stream:get_receiving_entity(Opening)),
|
||||
Server = binary_to_list(ServerB),
|
||||
case lists:member(Server, ?MYHOSTS) of
|
||||
case ?IS_MY_HOST(Server) of
|
||||
true ->
|
||||
Lang = exmpp_stream:get_lang(Opening),
|
||||
change_shaper(StateData,
|
||||
|
@ -46,6 +46,8 @@ config() ->
|
||||
check_database_modules() ->
|
||||
[check_database_module(M)||M<-get_db_used()].
|
||||
|
||||
check_database_module(host) ->
|
||||
ok;
|
||||
check_database_module(odbc) ->
|
||||
check_modules(odbc, [odbc, odbc_app, odbc_sup, ejabberd_odbc, ejabberd_odbc_sup, odbc_queries]);
|
||||
check_database_module(mysql) ->
|
||||
|
@ -27,17 +27,32 @@
|
||||
-module(ejabberd_config).
|
||||
-author('alexey@process-one.net').
|
||||
|
||||
-export([start/0, load_file/1,
|
||||
-export([start/0, load_file/1, get_host_option/2,
|
||||
add_global_option/2, add_local_option/2,
|
||||
mne_add_local_option/2, mne_del_local_option/1,
|
||||
del_global_option/1, del_local_option/1,
|
||||
get_global_option/1, get_local_option/1]).
|
||||
|
||||
-export([for_host/1
|
||||
,configure_host/2
|
||||
,delete_host/1
|
||||
]).
|
||||
|
||||
-export([search/1]).
|
||||
|
||||
-export([get_vh_by_auth_method/1]).
|
||||
-export([is_file_readable/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("ejabberd_config.hrl").
|
||||
-include_lib("kernel/include/file.hrl").
|
||||
-include_lib("stdlib/include/ms_transform.hrl").
|
||||
|
||||
-record(state, {opts = [],
|
||||
hosts = [],
|
||||
override_local = false,
|
||||
override_global = false,
|
||||
override_acls = false}).
|
||||
|
||||
%% @type macro() = {macro_key(), macro_value()}
|
||||
|
||||
@ -153,6 +168,14 @@ search_hosts(Term, State) ->
|
||||
|
||||
add_hosts_to_option(Hosts, State) ->
|
||||
PrepHosts = normalize_hosts(Hosts),
|
||||
mnesia:transaction(
|
||||
fun() ->
|
||||
lists:foreach(
|
||||
fun(H) ->
|
||||
mnesia:write(#local_config{key = {H, host},
|
||||
value = []})
|
||||
end, PrepHosts)
|
||||
end),
|
||||
add_option(hosts, PrepHosts, State#state{hosts = PrepHosts}).
|
||||
|
||||
normalize_hosts(Hosts) ->
|
||||
@ -379,6 +402,8 @@ process_term(Term, State) ->
|
||||
{host_config, Host, Terms} ->
|
||||
lists:foldl(fun(T, S) -> process_host_term(T, Host, S) end,
|
||||
State, Terms);
|
||||
{clusterid, ClusterID} ->
|
||||
add_option(clusterid, ClusterID, State);
|
||||
{listen, Listeners} ->
|
||||
Listeners2 =
|
||||
lists:map(
|
||||
@ -443,8 +468,7 @@ process_term(Term, State) ->
|
||||
{max_fsm_queue, N} ->
|
||||
add_option(max_fsm_queue, N, State);
|
||||
{_Opt, _Val} ->
|
||||
lists:foldl(fun(Host, S) -> process_host_term(Term, Host, S) end,
|
||||
State, State#state.hosts)
|
||||
process_host_term(Term, global, State)
|
||||
end.
|
||||
|
||||
process_host_term(Term, Host, State) ->
|
||||
@ -569,10 +593,11 @@ add_global_option(Opt, Val) ->
|
||||
end).
|
||||
|
||||
add_local_option(Opt, Val) ->
|
||||
mnesia:transaction(fun() ->
|
||||
mnesia:write(#local_config{key = Opt,
|
||||
value = Val})
|
||||
end).
|
||||
mnesia:transaction(fun mne_add_local_option/2, [Opt, Val]).
|
||||
|
||||
mne_add_local_option(Opt, Val) ->
|
||||
mnesia:write(#local_config{key = Opt,
|
||||
value = Val}).
|
||||
|
||||
del_global_option(Opt) ->
|
||||
mnesia:transaction(fun() ->
|
||||
@ -585,6 +610,13 @@ del_local_option(Opt) ->
|
||||
end).
|
||||
|
||||
|
||||
get_global_option({Opt1, Host} = Opt) when is_list(Host) ->
|
||||
case ets:lookup(config, Opt) of
|
||||
[#config{value = Val}] ->
|
||||
Val;
|
||||
_ ->
|
||||
get_global_option({Opt1, global})
|
||||
end;
|
||||
get_global_option(Opt) ->
|
||||
case ets:lookup(config, Opt) of
|
||||
[#config{value = Val}] ->
|
||||
@ -593,6 +625,13 @@ get_global_option(Opt) ->
|
||||
undefined
|
||||
end.
|
||||
|
||||
get_local_option({Opt1, Host} = Opt) when is_list(Host) ->
|
||||
case ets:lookup(local_config, Opt) of
|
||||
[#local_config{value = Val}] ->
|
||||
Val;
|
||||
_ ->
|
||||
get_local_option({Opt1, global})
|
||||
end;
|
||||
get_local_option(Opt) ->
|
||||
case ets:lookup(local_config, Opt) of
|
||||
[#local_config{value = Val}] ->
|
||||
@ -601,6 +640,17 @@ get_local_option(Opt) ->
|
||||
undefined
|
||||
end.
|
||||
|
||||
get_host_option(Host, Option) ->
|
||||
case ets:lookup(local_config, {Option, Host}) of
|
||||
[#local_config{value=V}] -> V;
|
||||
_ -> undefined
|
||||
end.
|
||||
|
||||
mne_del_local_option({_OptName, Host} = Opt) when is_list(Host) ->
|
||||
mnesia:delete({local_config, Opt});
|
||||
mne_del_local_option({Host, host} = Opt) when is_list(Host) ->
|
||||
mnesia:delete({local_config, Opt}).
|
||||
|
||||
%% Return the list of hosts handled by a given module
|
||||
get_vh_by_auth_method(AuthMethod) ->
|
||||
mnesia:dirty_select(local_config,
|
||||
@ -619,3 +669,54 @@ is_file_readable(Path) ->
|
||||
{error, _Reason} ->
|
||||
false
|
||||
end.
|
||||
|
||||
search(Pattern) ->
|
||||
{atomic, Res} = mnesia:transaction(fun mnesia:select/2, [local_config, Pattern]),
|
||||
Res.
|
||||
|
||||
for_host(Host) ->
|
||||
mnesia:read({local_config, {Host, host}})
|
||||
++ mnesia:select(local_config,
|
||||
ets:fun2ms(fun (#local_config{key={_, H}})
|
||||
when H =:= Host ->
|
||||
object()
|
||||
end))
|
||||
++ acl:for_host(Host).
|
||||
|
||||
delete_host(Host) ->
|
||||
mnesia_delete_objects(for_host(Host)),
|
||||
ok.
|
||||
|
||||
configure_host(Host, Config) ->
|
||||
HostExistenceTerm = {{Host, host}, []},
|
||||
Records = host_terms_to_records(Host, [HostExistenceTerm | Config]),
|
||||
mnesia_write_objects(Records),
|
||||
ok.
|
||||
|
||||
host_terms_to_records(Host, Terms) ->
|
||||
lists:foldl(fun (Term, Acc) ->
|
||||
host_term_to_record(Term, Host, Acc)
|
||||
end, [], Terms).
|
||||
|
||||
host_term_to_record({acl, ACLName, ACLData}, Host, Acc) ->
|
||||
[acl:to_record(Host, ACLName, ACLData) | Acc];
|
||||
host_term_to_record({access, RuleName, Rules}, Host, Acc) ->
|
||||
[#config{key={access, RuleName, Host}, value=Rules} | Acc];
|
||||
host_term_to_record({shaper, Name, Data}, Host, Acc) ->
|
||||
[#config{key={shaper, Name, Host}, value=Data} | Acc];
|
||||
host_term_to_record({host, _}, _Host, Acc) -> Acc;
|
||||
host_term_to_record({hosts, _}, _Host, Acc) -> Acc;
|
||||
host_term_to_record({{Host, host}, []}, Host, Acc) ->
|
||||
[#local_config{key={Host, host}, value=[]} | Acc];
|
||||
host_term_to_record({Opt, Val}, Host, Acc) when is_atom(Opt) ->
|
||||
[#local_config{key={Opt, Host}, value=Val} | Acc].
|
||||
|
||||
|
||||
mnesia_delete_objects(List) when is_list(List) ->
|
||||
true = lists:all(fun (I) ->
|
||||
ok =:= mnesia:delete_object(I)
|
||||
end, List).
|
||||
mnesia_write_objects(List) when is_list(List) ->
|
||||
true = lists:all(fun (I) ->
|
||||
ok =:= mnesia:write(I)
|
||||
end, List).
|
||||
|
@ -21,8 +21,3 @@
|
||||
|
||||
-record(config, {key, value}).
|
||||
-record(local_config, {key, value}).
|
||||
-record(state, {opts = [],
|
||||
hosts = [],
|
||||
override_local = false,
|
||||
override_global = false,
|
||||
override_acls = false}).
|
||||
|
@ -119,14 +119,27 @@ delete_dist(Hook, Host, Node, Module, Function, Seq) ->
|
||||
%% @doc Run the calls of this hook in order, don't care about function results.
|
||||
%% If a call returns stop, no more calls are performed.
|
||||
run(Hook, Args) ->
|
||||
run(Hook, global, Args).
|
||||
runx(Hook, global, Args).
|
||||
|
||||
run(Hook, Host, Args) when is_binary(Host) orelse is_atom(Host) ->
|
||||
case ets:lookup(hooks, {Hook, Host}) of
|
||||
run(Hook, Host, Args) when is_binary(Host) ->
|
||||
case runx(Hook, Host, Args) of
|
||||
stop -> stop;
|
||||
_ -> runx(Hook, global, Args)
|
||||
end;
|
||||
run(Hook, Host, Args) when Host == global ->
|
||||
runx(Hook, Host, Args).
|
||||
|
||||
runx(Hook, Host, Args) when is_binary(Host) orelse is_atom(Host) ->
|
||||
case ets:lookup(hooks, {Hook, ejabberd:normalize_host(Host)}) of
|
||||
[{_, Ls}] ->
|
||||
run1(Ls, Hook, Args);
|
||||
[] ->
|
||||
ok
|
||||
case ets:lookup(hooks, {Hook, global}) of
|
||||
[{_, Ls}] ->
|
||||
run1(Ls, Hook, Args);
|
||||
[] ->
|
||||
ok
|
||||
end
|
||||
end.
|
||||
|
||||
%% @spec (Hook::atom(), Val, Args) -> Val | stopped | NewVal
|
||||
@ -136,16 +149,29 @@ run(Hook, Host, Args) when is_binary(Host) orelse is_atom(Host) ->
|
||||
%% If a call returns 'stop', no more calls are performed and 'stopped' is returned.
|
||||
%% If a call returns {stopped, NewVal}, no more calls are performed and NewVal is returned.
|
||||
run_fold(Hook, Val, Args) ->
|
||||
run_fold(Hook, global, Val, Args).
|
||||
run_foldx(Hook, global, Val, Args).
|
||||
|
||||
%% @spec (Hook::atom(), Host, Val, Args) -> Val | stopped | NewVal
|
||||
%% Host = global | binary()
|
||||
run_fold(Hook, Host, Val, Args) when is_binary(Host) orelse is_atom(Host) ->
|
||||
case ets:lookup(hooks, {Hook, Host}) of
|
||||
run_fold(Hook, Host, Val, Args) when is_binary(Host) ->
|
||||
case run_foldx(Hook, Host, Val, Args) of
|
||||
stopped -> stopped;
|
||||
Val2 -> run_foldx(Hook, global, Val2, Args)
|
||||
end;
|
||||
run_fold(Hook, Host, Val, Args) when Host == global ->
|
||||
run_foldx(Hook, Host, Val, Args).
|
||||
|
||||
run_foldx(Hook, Host, Val, Args) ->
|
||||
case ets:lookup(hooks, {Hook, ejabberd:normalize_host(Host)}) of
|
||||
[{_, Ls}] ->
|
||||
run_fold1(Ls, Hook, Val, Args);
|
||||
[] ->
|
||||
Val
|
||||
case ets:lookup(hooks, {Hook, global}) of
|
||||
[{_, Ls}] ->
|
||||
run_fold1(Ls, Hook, Val, Args);
|
||||
[] ->
|
||||
Val
|
||||
end
|
||||
end.
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
@ -173,7 +199,8 @@ init([]) ->
|
||||
%% {stop, Reason, State} (terminate/2 is called)
|
||||
%%----------------------------------------------------------------------
|
||||
handle_call({add, Hook, Host, Module, Function, Seq}, _From, State) ->
|
||||
Reply = case ets:lookup(hooks, {Hook, Host}) of
|
||||
NHost = ejabberd:normalize_host(Host),
|
||||
Reply = case ets:lookup(hooks, {Hook, NHost}) of
|
||||
[{_, Ls}] ->
|
||||
El = {Seq, Module, Function},
|
||||
case lists:member(El, Ls) of
|
||||
@ -181,12 +208,12 @@ handle_call({add, Hook, Host, Module, Function, Seq}, _From, State) ->
|
||||
ok;
|
||||
false ->
|
||||
NewLs = lists:merge(Ls, [El]),
|
||||
ets:insert(hooks, {{Hook, Host}, NewLs}),
|
||||
ets:insert(hooks, {{Hook, NHost}, NewLs}),
|
||||
ok
|
||||
end;
|
||||
[] ->
|
||||
NewLs = [{Seq, Module, Function}],
|
||||
ets:insert(hooks, {{Hook, Host}, NewLs}),
|
||||
ets:insert(hooks, {{Hook, NHost}, NewLs}),
|
||||
ok
|
||||
end,
|
||||
{reply, Reply, State};
|
||||
@ -209,10 +236,11 @@ handle_call({add, Hook, Host, Node, Module, Function, Seq}, _From, State) ->
|
||||
end,
|
||||
{reply, Reply, State};
|
||||
handle_call({delete, Hook, Host, Module, Function, Seq}, _From, State) ->
|
||||
Reply = case ets:lookup(hooks, {Hook, Host}) of
|
||||
NHost = ejabberd:normalize_host(Host),
|
||||
Reply = case ets:lookup(hooks, {Hook, NHost}) of
|
||||
[{_, Ls}] ->
|
||||
NewLs = lists:delete({Seq, Module, Function}, Ls),
|
||||
ets:insert(hooks, {{Hook, Host}, NewLs}),
|
||||
ets:insert(hooks, {{Hook, NHost}, NewLs}),
|
||||
ok;
|
||||
[] ->
|
||||
ok
|
||||
|
@ -82,7 +82,7 @@ process_iq(From, To, Packet) ->
|
||||
case exmpp_iq:xmlel_to_iq(Packet) of
|
||||
#iq{kind = request, ns = XMLNS} = IQ_Rec ->
|
||||
Host = exmpp_jid:prep_domain(To),
|
||||
case ets:lookup(?IQTABLE, {XMLNS, Host}) of
|
||||
case ets:lookup(?IQTABLE, {XMLNS, ejabberd:normalize_host(Host)}) of
|
||||
[{_, Module, Function}] ->
|
||||
ResIQ = Module:Function(From, To, IQ_Rec),
|
||||
if
|
||||
@ -96,8 +96,15 @@ process_iq(From, To, Packet) ->
|
||||
gen_iq_handler:handle(Host, Module, Function, Opts,
|
||||
From, To, IQ_Rec);
|
||||
[] ->
|
||||
Err = exmpp_iq:error(Packet, 'feature-not-implemented'),
|
||||
ejabberd_router:route(To, From, Err)
|
||||
case ets:lookup(?IQTABLE, {XMLNS, global}) of
|
||||
[{_, Module, Function, Opts}] ->
|
||||
gen_iq_handler:handle(
|
||||
global, Module, Function, Opts,
|
||||
From, To, IQ_Rec);
|
||||
[] ->
|
||||
Err = exmpp_iq:error(Packet, 'feature-not-implemented'),
|
||||
ejabberd_router:route(To, From, Err)
|
||||
end
|
||||
end;
|
||||
#iq{kind = response} = IQReply ->
|
||||
%%IQReply = jlib:iq_query_or_response_info(IQ_Rec),
|
||||
@ -193,10 +200,10 @@ bounce_resource_packet(From, To, Packet) ->
|
||||
init([]) ->
|
||||
lists:foreach(
|
||||
fun(Host) ->
|
||||
ejabberd_router:register_route(Host, {apply, ?MODULE, route}),
|
||||
ejabberd_hooks:add(local_send_to_resource_hook, list_to_binary(Host),
|
||||
?MODULE, bounce_resource_packet, 100)
|
||||
ejabberd_router:register_route(Host, {apply, ?MODULE, route})
|
||||
end, ?MYHOSTS),
|
||||
ejabberd_hooks:add(local_send_to_resource_hook, global,
|
||||
?MODULE, bounce_resource_packet, 100),
|
||||
catch ets:new(?IQTABLE, [named_table, public]),
|
||||
mnesia:delete_table(iq_response),
|
||||
catch ets:new(iq_response, [named_table, public,
|
||||
@ -253,21 +260,21 @@ handle_info({route, From, To, Packet}, State) ->
|
||||
end,
|
||||
{noreply, State};
|
||||
handle_info({register_iq_handler, Host, XMLNS, Module, Function}, State) ->
|
||||
ets:insert(?IQTABLE, {{XMLNS, Host}, Module, Function}),
|
||||
ets:insert(?IQTABLE, {{XMLNS, ejabberd:normalize_host(Host)}, Module, Function}),
|
||||
catch mod_disco:register_feature(Host, XMLNS),
|
||||
{noreply, State};
|
||||
handle_info({register_iq_handler, Host, XMLNS, Module, Function, Opts}, State) ->
|
||||
ets:insert(?IQTABLE, {{XMLNS, Host}, Module, Function, Opts}),
|
||||
ets:insert(?IQTABLE, {{XMLNS, ejabberd:normalize_host(Host)}, Module, Function, Opts}),
|
||||
catch mod_disco:register_feature(Host, XMLNS),
|
||||
{noreply, State};
|
||||
handle_info({unregister_iq_handler, Host, XMLNS}, State) ->
|
||||
case ets:lookup(?IQTABLE, {XMLNS, Host}) of
|
||||
case ets:lookup(?IQTABLE, {XMLNS, ejabberd:normalize_host(Host)}) of
|
||||
[{_, Module, Function, Opts}] ->
|
||||
gen_iq_handler:stop_iq_handler(Module, Function, Opts);
|
||||
_ ->
|
||||
ok
|
||||
end,
|
||||
ets:delete(?IQTABLE, {XMLNS, Host}),
|
||||
ets:delete(?IQTABLE, {XMLNS, ejabberd:normalize_host(Host)}),
|
||||
catch mod_disco:unregister_feature(Host, XMLNS),
|
||||
{noreply, State};
|
||||
handle_info(refresh_iq_handlers, State) ->
|
||||
|
@ -27,8 +27,15 @@
|
||||
-module(ejabberd_rdbms).
|
||||
-author('alexey@process-one.net').
|
||||
|
||||
-export([start/0]).
|
||||
-export([start/0
|
||||
,start_odbc/1
|
||||
,stop_odbc/1
|
||||
,running/1
|
||||
]).
|
||||
-include("ejabberd.hrl").
|
||||
-include("ejabberd_config.hrl").
|
||||
-include_lib("stdlib/include/ms_transform.hrl").
|
||||
-define(SUPERVISOR, ejabberd_sup).
|
||||
|
||||
start() ->
|
||||
%% Check if ejabberd has been compiled with ODBC
|
||||
@ -52,22 +59,39 @@ start_hosts() ->
|
||||
|
||||
%% Start the ODBC module on the given host
|
||||
start_odbc(Host) ->
|
||||
Supervisor_name = gen_mod:get_module_proc(Host, ejabberd_odbc_sup),
|
||||
SupervisorName = sup_name(Host),
|
||||
ChildSpec =
|
||||
{Supervisor_name,
|
||||
{SupervisorName,
|
||||
{ejabberd_odbc_sup, start_link, [Host]},
|
||||
transient,
|
||||
infinity,
|
||||
supervisor,
|
||||
[ejabberd_odbc_sup]},
|
||||
case supervisor:start_child(ejabberd_sup, ChildSpec) of
|
||||
case supervisor:start_child(?SUPERVISOR, ChildSpec) of
|
||||
{ok, _PID} ->
|
||||
ok;
|
||||
_Error ->
|
||||
?ERROR_MSG("Start of supervisor ~p failed:~n~p~nRetrying...~n", [Supervisor_name, _Error]),
|
||||
?ERROR_MSG("Start of supervisor ~p failed:~n~p~nRetrying...~n", [SupervisorName, _Error]),
|
||||
start_odbc(Host)
|
||||
end.
|
||||
|
||||
stop_odbc(Host) ->
|
||||
SupervisorName = sup_name(Host),
|
||||
case running(Host) of
|
||||
false -> ok;
|
||||
true ->
|
||||
case [H || H <- dependent_hosts(Host), ejabberd_hosts:running(H)] of
|
||||
[] ->
|
||||
?INFO_MSG("About to terminate ~p", [SupervisorName]),
|
||||
ok = supervisor:terminate_child(?SUPERVISOR, SupervisorName),
|
||||
ok = supervisor:delete_child(?SUPERVISOR, SupervisorName);
|
||||
RunningHosts ->
|
||||
?WARNING_MSG("Not stopping ODBC for ~p because the virtual hosts ~p are still using it.",
|
||||
[Host, RunningHosts]),
|
||||
{error, still_in_use}
|
||||
end
|
||||
end.
|
||||
|
||||
%% Returns true if we have configured odbc_server for the given host
|
||||
needs_odbc(Host) ->
|
||||
try
|
||||
@ -75,9 +99,32 @@ needs_odbc(Host) ->
|
||||
case ejabberd_config:get_local_option({odbc_server, LHost}) of
|
||||
undefined ->
|
||||
false;
|
||||
_ -> true
|
||||
{host, _} ->
|
||||
false;
|
||||
_ ->
|
||||
true
|
||||
end
|
||||
catch
|
||||
_ ->
|
||||
false
|
||||
end.
|
||||
|
||||
running(Host) ->
|
||||
Supervisors = supervisor:which_children(?SUPERVISOR),
|
||||
SupervisorName = gen_mod:get_module_proc(Host, ejabberd_odbc_sup),
|
||||
case lists:keysearch(SupervisorName, 1, Supervisors) of
|
||||
false -> false;
|
||||
{value, Cspec} when is_tuple(Cspec) -> true
|
||||
end.
|
||||
|
||||
|
||||
dependent_hosts(Host) ->
|
||||
MS = ets:fun2ms(fun (#local_config{key={odbc_server, DHost},
|
||||
value={host, H}})
|
||||
when H =:= Host ->
|
||||
DHost
|
||||
end),
|
||||
ejabberd_config:search(MS).
|
||||
|
||||
sup_name(Host) ->
|
||||
gen_mod:get_module_proc(Host, ejabberd_odbc_sup).
|
||||
|
@ -36,9 +36,11 @@
|
||||
register_route/2,
|
||||
register_routes/1,
|
||||
unregister_route/1,
|
||||
force_unregister_route/1,
|
||||
unregister_routes/1,
|
||||
dirty_get_all_routes/0,
|
||||
dirty_get_all_domains/0,
|
||||
read_route/1,
|
||||
make_id/0
|
||||
]).
|
||||
|
||||
@ -98,56 +100,24 @@ route_error(From, To, ErrPacket, OrigPacket) ->
|
||||
ok
|
||||
end.
|
||||
|
||||
register_route(Domain) ->
|
||||
register_route({global, Prefix}) ->
|
||||
ejabberd_global_router:register_route(Prefix);
|
||||
register_route(Domain) when is_list(Domain) ->
|
||||
register_route(Domain, undefined).
|
||||
|
||||
register_route(Domain, LocalHint) ->
|
||||
try
|
||||
LDomain = exmpp_stringprep:nameprep(Domain),
|
||||
LDomainB = list_to_binary(LDomain),
|
||||
Pid = self(),
|
||||
case get_component_number(LDomain) of
|
||||
undefined ->
|
||||
F = fun() ->
|
||||
mnesia:write(#route{domain = LDomainB,
|
||||
pid = Pid,
|
||||
local_hint = LocalHint})
|
||||
end,
|
||||
mnesia:transaction(F);
|
||||
N ->
|
||||
F = fun() ->
|
||||
case mnesia:wread({route, LDomainB}) of
|
||||
[] ->
|
||||
mnesia:write(
|
||||
#route{domain = LDomainB,
|
||||
pid = Pid,
|
||||
local_hint = 1}),
|
||||
lists:foreach(
|
||||
fun(I) ->
|
||||
mnesia:write(
|
||||
#route{domain = LDomainB,
|
||||
pid = undefined,
|
||||
local_hint = I})
|
||||
end, lists:seq(2, N));
|
||||
Rs ->
|
||||
lists:any(
|
||||
fun(#route{pid = undefined,
|
||||
local_hint = I} = R) ->
|
||||
mnesia:write(
|
||||
#route{domain = LDomainB,
|
||||
pid = Pid,
|
||||
local_hint = I}),
|
||||
mnesia:delete_object(R),
|
||||
true;
|
||||
(_) ->
|
||||
false
|
||||
end, Rs)
|
||||
end
|
||||
end,
|
||||
mnesia:transaction(F)
|
||||
end
|
||||
LDomain = exmpp_stringprep:nameprep(Domain),
|
||||
LDomainB = list_to_binary(LDomain),
|
||||
Pid = self(),
|
||||
case get_component_number(LDomain) of
|
||||
undefined ->
|
||||
mnesia:transaction(fun register_simple_route/3, [LDomainB, Pid, LocalHint]);
|
||||
N ->
|
||||
mnesia:transaction(fun register_balanced_route/3, [LDomainB, Pid, N])
|
||||
end
|
||||
catch
|
||||
_ ->
|
||||
_ ->
|
||||
erlang:error({invalid_domain, Domain})
|
||||
end.
|
||||
|
||||
@ -156,53 +126,112 @@ register_routes(Domains) ->
|
||||
register_route(Domain)
|
||||
end, Domains).
|
||||
|
||||
unregister_route(Domain) ->
|
||||
register_simple_route(LDomain, Pid, LocalHint) ->
|
||||
mnesia:write(#route{domain = LDomain,
|
||||
pid = Pid,
|
||||
local_hint = LocalHint}).
|
||||
|
||||
register_balanced_route(LDomain, Pid, N) ->
|
||||
case mnesia:read({route, LDomain}) of
|
||||
[] ->
|
||||
mnesia:write(
|
||||
#route{domain = LDomain,
|
||||
pid = Pid,
|
||||
local_hint = 1}),
|
||||
lists:foreach(
|
||||
fun(I) ->
|
||||
mnesia:write(
|
||||
#route{domain = LDomain,
|
||||
pid = undefined,
|
||||
local_hint = I})
|
||||
end, lists:seq(2, N));
|
||||
Rs ->
|
||||
lists:any(
|
||||
fun(#route{pid = undefined,
|
||||
local_hint = I} = R) ->
|
||||
mnesia:write(
|
||||
#route{domain = LDomain,
|
||||
pid = Pid,
|
||||
local_hint = I}),
|
||||
mnesia:delete_object(R),
|
||||
true;
|
||||
(_) ->
|
||||
false
|
||||
end, Rs)
|
||||
end.
|
||||
|
||||
unregister_route({global, Prefix}) ->
|
||||
ejabberd_global_router:unregister_route(Prefix);
|
||||
unregister_route(Domain) when is_list(Domain) ->
|
||||
try
|
||||
LDomain = exmpp_stringprep:nameprep(Domain),
|
||||
LDomainB = list_to_binary(LDomain),
|
||||
Pid = self(),
|
||||
case get_component_number(LDomain) of
|
||||
undefined ->
|
||||
F = fun() ->
|
||||
case mnesia:match_object(
|
||||
#route{domain = LDomainB,
|
||||
pid = Pid,
|
||||
_ = '_'}) of
|
||||
[R] ->
|
||||
mnesia:delete_object(R);
|
||||
_ ->
|
||||
ok
|
||||
end
|
||||
end,
|
||||
mnesia:transaction(F);
|
||||
mnesia:transaction(fun delete_simple_route/2, [LDomainB, Pid]);
|
||||
_ ->
|
||||
F = fun() ->
|
||||
case mnesia:match_object(#route{domain=LDomainB,
|
||||
pid = Pid,
|
||||
_ = '_'}) of
|
||||
[R] ->
|
||||
I = R#route.local_hint,
|
||||
mnesia:write(
|
||||
#route{domain = LDomainB,
|
||||
pid = undefined,
|
||||
local_hint = I}),
|
||||
mnesia:delete_object(R);
|
||||
_ ->
|
||||
ok
|
||||
end
|
||||
end,
|
||||
mnesia:transaction(F)
|
||||
mnesia:transaction(fun delete_balanced_route/2, [LDomainB, Pid])
|
||||
end
|
||||
catch
|
||||
_ ->
|
||||
erlang:error({invalid_domain, Domain})
|
||||
end.
|
||||
|
||||
delete_simple_route(LDomain, Pid) ->
|
||||
case mnesia:match_object(#route{domain = LDomain,
|
||||
pid = Pid,
|
||||
_ = '_'}) of
|
||||
[R] ->
|
||||
mnesia:delete_object(R);
|
||||
_ ->
|
||||
ok
|
||||
end.
|
||||
|
||||
delete_balanced_route(LDomain, Pid) ->
|
||||
case mnesia:match_object(#route{domain=LDomain,
|
||||
pid = Pid,
|
||||
_ = '_'}) of
|
||||
[R] ->
|
||||
I = R#route.local_hint,
|
||||
ok = mnesia:write(
|
||||
#route{domain = LDomain,
|
||||
pid = undefined,
|
||||
local_hint = I}),
|
||||
mnesia:delete_object(R);
|
||||
_ ->
|
||||
ok
|
||||
end.
|
||||
|
||||
|
||||
force_unregister_route(Domain) ->
|
||||
case jlib:nameprep(Domain) of
|
||||
error ->
|
||||
erlang:error({invalid_domain, Domain});
|
||||
LDomain ->
|
||||
F = fun() ->
|
||||
case mnesia:match_object(
|
||||
#route{domain = LDomain,
|
||||
_ = '_'}) of
|
||||
Rs when is_list(Rs) ->
|
||||
lists:foreach(fun(R) ->
|
||||
mnesia:delete_object(R)
|
||||
end, Rs);
|
||||
_ ->
|
||||
ok
|
||||
end
|
||||
end,
|
||||
mnesia:transaction(F)
|
||||
end.
|
||||
|
||||
unregister_routes(Domains) ->
|
||||
lists:foreach(fun(Domain) ->
|
||||
unregister_route(Domain)
|
||||
end, Domains).
|
||||
|
||||
read_route(Domain) ->
|
||||
[{D,P,H}
|
||||
|| #route{domain=D, pid=P, local_hint=H} <- mnesia:dirty_read({route, Domain})].
|
||||
|
||||
dirty_get_all_routes() ->
|
||||
lists:usort(
|
||||
@ -376,10 +405,16 @@ do_route(OrigFrom, OrigTo, OrigPacket) ->
|
||||
case ejabberd_hooks:run_fold(filter_packet,
|
||||
{OrigFrom, OrigTo, OrigPacket}, []) of
|
||||
{From, To, Packet} ->
|
||||
LDomain = exmpp_jid:prep_domain(To),
|
||||
case mnesia:dirty_read(route, LDomain) of
|
||||
LDstDomain = exmpp_jid:prep_domain_as_list(To),
|
||||
Destination = ejabberd:normalize_host(LDstDomain),
|
||||
case mnesia:dirty_read(route, list_to_binary(Destination)) of
|
||||
[] ->
|
||||
ejabberd_s2s:route(From, To, Packet);
|
||||
case ejabberd_global_router:find_route(Destination) of
|
||||
no_route ->
|
||||
ejabberd_s2s:route(From, To, Packet);
|
||||
Route ->
|
||||
ejabberd_global_router:route(Route, From, To, Packet)
|
||||
end;
|
||||
[R] ->
|
||||
Pid = R#route.pid,
|
||||
if
|
||||
@ -396,7 +431,6 @@ do_route(OrigFrom, OrigTo, OrigPacket) ->
|
||||
drop
|
||||
end;
|
||||
Rs ->
|
||||
LDstDomain = exmpp_jid:prep_domain_as_list(To),
|
||||
Value = case ejabberd_config:get_local_option(
|
||||
{domain_balancing, LDstDomain}) of
|
||||
undefined -> now();
|
||||
|
@ -353,6 +353,12 @@ init([]) ->
|
||||
mnesia:add_table_index(session, us),
|
||||
mnesia:add_table_copy(session, node(), ram_copies),
|
||||
ets:new(sm_iqtable, [named_table]),
|
||||
ejabberd_hooks:add(roster_in_subscription, global,
|
||||
ejabberd_sm, check_in_subscription, 20),
|
||||
ejabberd_hooks:add(offline_message_hook, global,
|
||||
ejabberd_sm, bounce_offline_message, 100),
|
||||
ejabberd_hooks:add(remove_user, global,
|
||||
ejabberd_sm, disconnect_removed_user, 100),
|
||||
ejabberd_hooks:add(node_hash_update, ?MODULE, migrate, 100),
|
||||
lists:foreach(
|
||||
fun(Host) ->
|
||||
@ -417,19 +423,19 @@ handle_info({route, From, To, Packet}, State) ->
|
||||
end,
|
||||
{noreply, State};
|
||||
handle_info({register_iq_handler, Host, XMLNS, Module, Function}, State) ->
|
||||
ets:insert(sm_iqtable, {{XMLNS, Host}, Module, Function}),
|
||||
ets:insert(sm_iqtable, {{XMLNS, ejabberd:normalize_host(Host)}, Module, Function}),
|
||||
{noreply, State};
|
||||
handle_info({register_iq_handler, Host, XMLNS, Module, Function, Opts}, State) ->
|
||||
ets:insert(sm_iqtable, {{XMLNS, Host}, Module, Function, Opts}),
|
||||
ets:insert(sm_iqtable, {{XMLNS, ejabberd:normalize_host(Host)}, Module, Function, Opts}),
|
||||
{noreply, State};
|
||||
handle_info({unregister_iq_handler, Host, XMLNS}, State) ->
|
||||
case ets:lookup(sm_iqtable, {XMLNS, Host}) of
|
||||
case ets:lookup(sm_iqtable, {XMLNS, ejabberd:normalize_host(Host)}) of
|
||||
[{_, Module, Function, Opts}] ->
|
||||
gen_iq_handler:stop_iq_handler(Module, Function, Opts);
|
||||
_ ->
|
||||
ok
|
||||
end,
|
||||
ets:delete(sm_iqtable, {XMLNS, Host}),
|
||||
ets:delete(sm_iqtable, {XMLNS, ejabberd:normalize_host(Host)}),
|
||||
{noreply, State};
|
||||
handle_info(_Info, State) ->
|
||||
{noreply, State}.
|
||||
@ -763,7 +769,7 @@ process_iq(From, To, Packet) ->
|
||||
case exmpp_iq:xmlel_to_iq(Packet) of
|
||||
#iq{kind = request, ns = XMLNS} = IQ_Rec ->
|
||||
LServer = exmpp_jid:prep_domain(To),
|
||||
case ets:lookup(sm_iqtable, {XMLNS, LServer}) of
|
||||
case ets:lookup(sm_iqtable, {XMLNS, ejabberd:normalize_host(LServer)}) of
|
||||
[{_, Module, Function}] ->
|
||||
ResIQ = Module:Function(From, To, IQ_Rec),
|
||||
if
|
||||
@ -774,11 +780,17 @@ process_iq(From, To, Packet) ->
|
||||
ok
|
||||
end;
|
||||
[{_, Module, Function, Opts}] ->
|
||||
gen_iq_handler:handle(LServer,
|
||||
Module, Function, Opts, From, To, IQ_Rec);
|
||||
gen_iq_handler:handle(LServer,
|
||||
Module, Function, Opts, From, To, IQ_Rec);
|
||||
[] ->
|
||||
Err = exmpp_iq:error(Packet, 'service-unavailable'),
|
||||
ejabberd_router:route(To, From, Err)
|
||||
case ets:lookup(sm_iqtable, {XMLNS, global}) of
|
||||
[{_, Module, Function, Opts}] ->
|
||||
gen_iq_handler:handle(global, Module, Function, Opts,
|
||||
From, To, IQ_Rec);
|
||||
[] ->
|
||||
Err = exmpp_iq:error(Packet, 'service-unavailable'),
|
||||
ejabberd_router:route(To, From, Err)
|
||||
end
|
||||
end;
|
||||
#iq{kind = response} ->
|
||||
ok;
|
||||
|
@ -42,13 +42,13 @@ init([]) ->
|
||||
brutal_kill,
|
||||
worker,
|
||||
[ejabberd_hooks]},
|
||||
SystemMonitor =
|
||||
{ejabberd_system_monitor,
|
||||
{ejabberd_system_monitor, start_link, []},
|
||||
GlobalRouter =
|
||||
{ejabberd_global_router,
|
||||
{ejabberd_global_router, start_link, []},
|
||||
permanent,
|
||||
brutal_kill,
|
||||
worker,
|
||||
[ejabberd_system_monitor]},
|
||||
[ejabberd_global_router]},
|
||||
Router =
|
||||
{ejabberd_router,
|
||||
{ejabberd_router, start_link, []},
|
||||
@ -137,6 +137,13 @@ init([]) ->
|
||||
infinity,
|
||||
supervisor,
|
||||
[ejabberd_tmp_sup]},
|
||||
Hosts =
|
||||
{ejabberd_hosts,
|
||||
{ejabberd_hosts, start_link, []},
|
||||
permanent,
|
||||
brutal_kill,
|
||||
worker,
|
||||
[ejabberd_hosts]},
|
||||
HTTPSupervisor =
|
||||
{ejabberd_http_sup,
|
||||
{ejabberd_tmp_sup, start_link,
|
||||
@ -186,8 +193,8 @@ init([]) ->
|
||||
[ejabberd_cluster]},
|
||||
{ok, {{one_for_one, 10, 1},
|
||||
[Hooks,
|
||||
GlobalRouter,
|
||||
Cluster,
|
||||
SystemMonitor,
|
||||
Router,
|
||||
Router_multicast,
|
||||
SM,
|
||||
@ -199,6 +206,7 @@ init([]) ->
|
||||
S2SInSupervisor,
|
||||
S2SOutSupervisor,
|
||||
ServiceSupervisor,
|
||||
Hosts,
|
||||
HTTPSupervisor,
|
||||
HTTPPollSupervisor,
|
||||
IQSupervisor,
|
||||
|
@ -57,8 +57,9 @@ if [ "$ERLANG_NODE_ARG" != "" ] ; then
|
||||
fi
|
||||
|
||||
# check the proper system user is used
|
||||
ID=`id -g`
|
||||
GIDS=`id -G`
|
||||
if [ `uname -s` = "SunOS" ]; then IDCMD=/usr/xpg4/bin/id; else IDCMD=id; fi
|
||||
ID=`$IDCMD -g`
|
||||
EJID=`$IDCMD -g $INSTALLUSER`
|
||||
EJID=`id -g $INSTALLUSER`
|
||||
EXEC_CMD="false"
|
||||
for GID in $GIDS; do
|
||||
@ -77,10 +78,13 @@ fi
|
||||
NAME=-name
|
||||
[ "$ERLANG_NODE" = "${ERLANG_NODE%.*}" ] && NAME=-sname
|
||||
|
||||
if [ "$FIREWALL_WINDOW" = "" ] ; then
|
||||
KERNEL_OPTS=""
|
||||
else
|
||||
KERNEL_OPTS="-kernel inet_dist_listen_min ${FIREWALL_WINDOW%-*} inet_dist_listen_max ${FIREWALL_WINDOW#*-}"
|
||||
KERNEL_OPTS=""
|
||||
if [ "$FIREWALL_WINDOW" != "" ] ; then
|
||||
KERNEL_OPTS="${KERNEL_OPTS} -kernel inet_dist_listen_min ${FIREWALL_WINDOW%-*} inet_dist_listen_max ${FIREWALL_WINDOW#*-}"
|
||||
fi
|
||||
|
||||
if [ "$DIST_INTERFACE" != "" ] ; then
|
||||
KERNEL_OPTS="${KERNEL_OPTS} -kernel inet_dist_use_interface \"${DIST_INTERFACE}\""
|
||||
fi
|
||||
|
||||
ERLANG_OPTS="+K $POLL -smp $SMP +P $ERL_PROCESSES $ERL_OPTIONS"
|
||||
@ -146,7 +150,7 @@ start ()
|
||||
$KERNEL_OPTS \
|
||||
-s ejabberd \
|
||||
-sasl sasl_error_logger \\{file,\\\"$SASL_LOG_PATH\\\"\\} \
|
||||
$ERLANG_OPTS $ARGS \"$@\" $ERL_ARGS"
|
||||
$ERLANG_OPTS -- $ARGS \"$@\" $ERL_ARGS"
|
||||
}
|
||||
|
||||
# attach to server
|
||||
@ -177,7 +181,7 @@ debug ()
|
||||
$NAME debug-${TTY}-${ERLANG_NODE} \
|
||||
-remsh $ERLANG_NODE \
|
||||
$KERNEL_OPTS \
|
||||
$ERLANG_OPTS $ARGS \"$@\" $ERL_ARGS"
|
||||
$ERLANG_OPTS -- $ARGS \"$@\" $ERL_ARGS"
|
||||
}
|
||||
|
||||
# start interactive server
|
||||
@ -209,7 +213,7 @@ live ()
|
||||
-mnesia dir \"\\\"$SPOOLDIR\\\"\" \
|
||||
$KERNEL_OPTS \
|
||||
-s ejabberd \
|
||||
$ERLANG_OPTS $ARGS \"$@\" $ERL_ARGS"
|
||||
$ERLANG_OPTS -- $ARGS \"$@\" $ERL_ARGS"
|
||||
}
|
||||
|
||||
etop()
|
||||
|
@ -261,7 +261,7 @@ export_private_storage(ServerS, Output) ->
|
||||
LXMLNS = ejabberd_odbc:escape(atom_to_list(XMLNS)),
|
||||
SData = ejabberd_odbc:escape(
|
||||
exmpp_xml:document_to_list(Data)),
|
||||
odbc_queries:set_private_data_sql(Username, LXMLNS, SData);
|
||||
odbc_queries:set_private_data_sql(LServer, Username, LXMLNS, SData);
|
||||
(_Host, _R) ->
|
||||
[]
|
||||
end).
|
||||
|
@ -40,6 +40,7 @@
|
||||
loaded_modules_with_opts/1,
|
||||
get_hosts/2,
|
||||
get_module_proc/2,
|
||||
expand_host_name/3,
|
||||
is_loaded/2]).
|
||||
|
||||
-export([behaviour_info/1]).
|
||||
@ -192,6 +193,9 @@ loaded_modules_with_opts(Host) ->
|
||||
[],
|
||||
[{{'$1', '$2'}}]}]).
|
||||
|
||||
set_module_opts_mnesia(global, _Module, _Opts) ->
|
||||
%% Modules on the global host are usually static, so we shouldn't manipulate them.
|
||||
ok;
|
||||
set_module_opts_mnesia(Host, Module, Opts) ->
|
||||
Modules = case ejabberd_config:get_local_option({modules, Host}) of
|
||||
undefined ->
|
||||
@ -203,6 +207,9 @@ set_module_opts_mnesia(Host, Module, Opts) ->
|
||||
Modules2 = [{Module, Opts} | Modules1],
|
||||
ejabberd_config:add_local_option({modules, Host}, Modules2).
|
||||
|
||||
del_module_mnesia(global, _Module) ->
|
||||
%% Modules on the global host are usually static, so we shouldn't manipulate them.
|
||||
ok;
|
||||
del_module_mnesia(Host, Module) ->
|
||||
Modules = case ejabberd_config:get_local_option({modules, Host}) of
|
||||
undefined ->
|
||||
@ -226,6 +233,8 @@ get_hosts(Opts, Prefix) ->
|
||||
Hosts
|
||||
end.
|
||||
|
||||
get_module_proc(global, Base) ->
|
||||
list_to_atom(atom_to_list(Base) ++ "__global");
|
||||
get_module_proc(Host, {frontend, Base}) ->
|
||||
get_module_proc("frontend_" ++ Host, Base);
|
||||
get_module_proc(Host, Base) ->
|
||||
@ -234,3 +243,11 @@ get_module_proc(Host, Base) ->
|
||||
is_loaded(Host, Module) ->
|
||||
ets:member(ejabberd_modules, {Module, Host}).
|
||||
|
||||
expand_host_name(Host, Opts, DefaultPrefix) ->
|
||||
case Host of
|
||||
global ->
|
||||
{global, gen_mod:get_opt(prefix, Opts, DefaultPrefix)};
|
||||
_ ->
|
||||
gen_mod:get_opt_host(Host, Opts, DefaultPrefix ++ ".@HOST@")
|
||||
end.
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
|
||||
%% External exports
|
||||
-export([start/1, start_link/2,
|
||||
running/1,
|
||||
sql_query/2,
|
||||
sql_query_t/1,
|
||||
sql_transaction/2,
|
||||
@ -106,6 +107,14 @@ sql_query_on_all_connections(Host, Query) ->
|
||||
erlang:now()}, ?TRANSACTION_TIMEOUT) end,
|
||||
lists:map(F, ejabberd_odbc_sup:get_pids(Host)).
|
||||
|
||||
%% Predicate returning true if there is an odbc process running for
|
||||
%% host Host, false otherwise.
|
||||
running(Host) ->
|
||||
case catch ejabberd_odbc_sup:get_random_pid(Host) of
|
||||
P when is_pid(P) -> true;
|
||||
{'EXIT', {noproc, _}} -> false
|
||||
end.
|
||||
|
||||
%% SQL transaction based on a list of queries
|
||||
%% This function automatically
|
||||
sql_transaction(Host, Queries) when is_list(Queries) ->
|
||||
@ -497,7 +506,11 @@ pgsql_to_odbc({ok, PGSQLResult}) ->
|
||||
|
||||
pgsql_item_to_odbc({"SELECT", Rows, Recs}) ->
|
||||
{selected,
|
||||
[element(1, Row) || Row <- Rows],
|
||||
[case Row of
|
||||
{desc, _, Col, _, _, _, _, _} -> Col; % Recent pgsql driver API change.
|
||||
_ -> element(1, Row)
|
||||
end
|
||||
|| Row <- Rows],
|
||||
[list_to_tuple(Rec) || Rec <- Recs]};
|
||||
pgsql_item_to_odbc("INSERT " ++ OIDN) ->
|
||||
[_OID, N] = string:tokens(OIDN, " "),
|
||||
@ -555,6 +568,7 @@ log(Level, Format, Args) ->
|
||||
?ERROR_MSG(Format, Args)
|
||||
end.
|
||||
|
||||
%% TODO: update this function to handle the case clase {host, VhostName}
|
||||
db_opts(Host) ->
|
||||
case ejabberd_config:get_local_option({odbc_server, Host}) of
|
||||
%% Default pgsql port
|
||||
|
@ -100,11 +100,16 @@ init([Host]) ->
|
||||
end, lists:seq(1, PoolSize))}}.
|
||||
|
||||
get_pids(Host) ->
|
||||
Rs = mnesia:dirty_read(sql_pool, Host),
|
||||
[R#sql_pool.pid || R <- Rs].
|
||||
case ejabberd_config:get_local_option({odbc_server, Host}) of
|
||||
{host, Host1} ->
|
||||
get_pids(Host1);
|
||||
_ ->
|
||||
Rs = mnesia:dirty_read(sql_pool, Host),
|
||||
[R#sql_pool.pid || R <- Rs]
|
||||
end.
|
||||
|
||||
get_random_pid(Host) ->
|
||||
Pids = get_pids(Host),
|
||||
Pids = get_pids(ejabberd:normalize_host(Host)),
|
||||
lists:nth(erlang:phash(now(), length(Pids)), Pids).
|
||||
|
||||
add_pid(Host, Pid) ->
|
||||
|
@ -20,21 +20,35 @@
|
||||
-- Needs MySQL (at least 4.0.x) with innodb back-end
|
||||
SET table_type=InnoDB;
|
||||
|
||||
CREATE TABLE hosts (
|
||||
clusterid integer NOT NULL,
|
||||
host varchar(250) NOT NULL PRIMARY KEY,
|
||||
config text NOT NULL
|
||||
) CHARACTER SET utf8;
|
||||
|
||||
INSERT INTO hosts (clusterid, host, config)
|
||||
VALUES (1, 'localhost', '');
|
||||
|
||||
CREATE TABLE users (
|
||||
username varchar(250) PRIMARY KEY,
|
||||
host varchar(250) NOT NULL,
|
||||
username varchar(250) NOT NULL,
|
||||
password text NOT NULL,
|
||||
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (host, username)
|
||||
) CHARACTER SET utf8;
|
||||
|
||||
|
||||
CREATE TABLE last (
|
||||
username varchar(250) PRIMARY KEY,
|
||||
host varchar(250) NOT NULL,
|
||||
username varchar(250) NOT NULL,
|
||||
seconds text NOT NULL,
|
||||
state text NOT NULl
|
||||
state text NOT NULL,
|
||||
PRIMARY KEY (host, username)
|
||||
) CHARACTER SET utf8;
|
||||
|
||||
|
||||
CREATE TABLE rosterusers (
|
||||
host varchar(250) NOT NULL,
|
||||
username varchar(250) NOT NULL,
|
||||
jid varchar(250) NOT NULL,
|
||||
nick text NOT NULL,
|
||||
@ -44,42 +58,44 @@ CREATE TABLE rosterusers (
|
||||
server character(1) NOT NULL,
|
||||
subscribe text NOT NULL,
|
||||
type text,
|
||||
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (host(75), username(75), jid(75))
|
||||
) CHARACTER SET utf8;
|
||||
|
||||
CREATE UNIQUE INDEX i_rosteru_user_jid ON rosterusers(username(75), jid(75));
|
||||
CREATE INDEX i_rosteru_username ON rosterusers(username);
|
||||
CREATE INDEX i_rosteru_jid ON rosterusers(jid);
|
||||
|
||||
CREATE TABLE rostergroups (
|
||||
host varchar(250) NOT NULL,
|
||||
username varchar(250) NOT NULL,
|
||||
jid varchar(250) NOT NULL,
|
||||
grp text NOT NULL
|
||||
grp text NOT NULL,
|
||||
PRIMARY KEY (host(75), username(75), jid(75))
|
||||
) CHARACTER SET utf8;
|
||||
|
||||
CREATE INDEX pk_rosterg_user_jid ON rostergroups(username(75), jid(75));
|
||||
|
||||
|
||||
CREATE TABLE spool (
|
||||
host varchar(250) NOT NULL,
|
||||
username varchar(250) NOT NULL,
|
||||
xml text NOT NULL,
|
||||
seq BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
|
||||
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (host, username, seq)
|
||||
) CHARACTER SET utf8;
|
||||
|
||||
CREATE INDEX i_despool USING BTREE ON spool(username);
|
||||
|
||||
|
||||
CREATE TABLE vcard (
|
||||
username varchar(250) PRIMARY KEY,
|
||||
host varchar(250) NOT NULL,
|
||||
username varchar(250) NOT NULL,
|
||||
vcard text NOT NULL,
|
||||
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (host, username)
|
||||
) CHARACTER SET utf8;
|
||||
|
||||
|
||||
CREATE TABLE vcard_search (
|
||||
host varchar(250) NOT NULL,
|
||||
username varchar(250) NOT NULL,
|
||||
lusername varchar(250) PRIMARY KEY,
|
||||
lusername varchar(250) NOT NULL,
|
||||
fn text NOT NULL,
|
||||
lfn varchar(250) NOT NULL,
|
||||
family text NOT NULL,
|
||||
@ -101,7 +117,8 @@ CREATE TABLE vcard_search (
|
||||
orgname text NOT NULL,
|
||||
lorgname varchar(250) NOT NULL,
|
||||
orgunit text NOT NULL,
|
||||
lorgunit varchar(250) NOT NULL
|
||||
lorgunit varchar(250) NOT NULL,
|
||||
PRIMARY KEY (host, lusername)
|
||||
) CHARACTER SET utf8;
|
||||
|
||||
CREATE INDEX i_vcard_search_lfn ON vcard_search(lfn);
|
||||
@ -117,20 +134,21 @@ CREATE INDEX i_vcard_search_lorgname ON vcard_search(lorgname);
|
||||
CREATE INDEX i_vcard_search_lorgunit ON vcard_search(lorgunit);
|
||||
|
||||
CREATE TABLE privacy_default_list (
|
||||
username varchar(250) PRIMARY KEY,
|
||||
name varchar(250) NOT NULL
|
||||
host varchar(250) NOT NULL,
|
||||
username varchar(250),
|
||||
name varchar(250) NOT NULL,
|
||||
PRIMARY KEY (host, username)
|
||||
) CHARACTER SET utf8;
|
||||
|
||||
CREATE TABLE privacy_list (
|
||||
host varchar(250) NOT NULL,
|
||||
username varchar(250) NOT NULL,
|
||||
name varchar(250) NOT NULL,
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
|
||||
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (host, username, name)
|
||||
) CHARACTER SET utf8;
|
||||
|
||||
CREATE INDEX i_privacy_list_username USING BTREE ON privacy_list(username);
|
||||
CREATE UNIQUE INDEX i_privacy_list_username_name USING BTREE ON privacy_list (username(75), name(75));
|
||||
|
||||
CREATE TABLE privacy_list_data (
|
||||
id bigint,
|
||||
t character(1) NOT NULL,
|
||||
@ -145,14 +163,15 @@ CREATE TABLE privacy_list_data (
|
||||
) CHARACTER SET utf8;
|
||||
|
||||
CREATE TABLE private_storage (
|
||||
host varchar(250) NOT NULL,
|
||||
username varchar(250) NOT NULL,
|
||||
namespace varchar(250) NOT NULL,
|
||||
data text NOT NULL,
|
||||
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (host(75), username(75), namespace(75))
|
||||
) CHARACTER SET utf8;
|
||||
|
||||
CREATE INDEX i_private_storage_username USING BTREE ON private_storage(username);
|
||||
CREATE UNIQUE INDEX i_private_storage_username_namespace USING BTREE ON private_storage(username(75), namespace(75));
|
||||
|
||||
-- Not tested in mysql
|
||||
CREATE TABLE roster_version (
|
||||
|
@ -41,7 +41,7 @@
|
||||
list_users/2,
|
||||
users_number/1,
|
||||
users_number/2,
|
||||
add_spool_sql/2,
|
||||
add_spool_sql/3,
|
||||
add_spool/2,
|
||||
get_and_del_spool_msg_t/2,
|
||||
del_spool_msg/2,
|
||||
@ -52,27 +52,27 @@
|
||||
get_roster_by_jid/3,
|
||||
get_rostergroup_by_jid/3,
|
||||
del_roster/3,
|
||||
del_roster_sql/2,
|
||||
del_roster_sql/3,
|
||||
update_roster/5,
|
||||
update_roster_sql/4,
|
||||
update_roster_sql/5,
|
||||
roster_subscribe/4,
|
||||
get_subscription/3,
|
||||
set_private_data/4,
|
||||
set_private_data_sql/3,
|
||||
set_private_data_sql/4,
|
||||
get_private_data/3,
|
||||
del_user_private_storage/2,
|
||||
get_default_privacy_list/2,
|
||||
get_default_privacy_list_t/1,
|
||||
get_default_privacy_list_t/2,
|
||||
get_privacy_list_names/2,
|
||||
get_privacy_list_names_t/1,
|
||||
get_privacy_list_names_t/2,
|
||||
get_privacy_list_id/3,
|
||||
get_privacy_list_id_t/2,
|
||||
get_privacy_list_id_t/3,
|
||||
get_privacy_list_data/3,
|
||||
get_privacy_list_data_by_id/2,
|
||||
set_default_privacy_list/2,
|
||||
set_default_privacy_list/3,
|
||||
unset_default_privacy_list/2,
|
||||
remove_privacy_list/2,
|
||||
add_privacy_list/2,
|
||||
remove_privacy_list/3,
|
||||
add_privacy_list/3,
|
||||
set_privacy_list/2,
|
||||
del_privacy_lists/3,
|
||||
set_vcard/26,
|
||||
@ -122,65 +122,75 @@ sql_transaction(LServer, F) ->
|
||||
ejabberd_odbc:sql_transaction(LServer, F).
|
||||
|
||||
get_last(LServer, Username) ->
|
||||
Host = escape(LServer),
|
||||
ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
["select seconds, state from last "
|
||||
"where username='", Username, "'"]).
|
||||
"where username='", Username, "' and host='", Host, "'"]).
|
||||
|
||||
set_last_t(LServer, Username, Seconds, State) ->
|
||||
Host = escape(LServer),
|
||||
%% MREMOND: I think this should be turn into a non transactional behaviour
|
||||
ejabberd_odbc:sql_transaction(
|
||||
LServer,
|
||||
fun() ->
|
||||
update_t("last", ["username", "seconds", "state"],
|
||||
[Username, Seconds, State],
|
||||
["username='", Username, "'"])
|
||||
update_t("last", ["username", "host", "seconds", "state"],
|
||||
[Username, Host, Seconds, State],
|
||||
["username='", Username, "' and host='", Host, "'"])
|
||||
end).
|
||||
|
||||
del_last(LServer, Username) ->
|
||||
Host = escape(LServer),
|
||||
ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
["delete from last where username='", Username, "'"]).
|
||||
["delete from last where username='", Username, "' and host='", Host, "'"]).
|
||||
|
||||
get_password(LServer, Username) ->
|
||||
Host = escape(LServer),
|
||||
ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
["select password from users "
|
||||
"where username='", Username, "';"]).
|
||||
"where username='", Username, "' and host='", Host, "';"]).
|
||||
|
||||
set_password_t(LServer, Username, Pass) ->
|
||||
Host = escape(LServer),
|
||||
ejabberd_odbc:sql_transaction(
|
||||
LServer,
|
||||
fun() ->
|
||||
update_t("users", ["username", "password"],
|
||||
[Username, Pass],
|
||||
["username='", Username ,"'"])
|
||||
update_t("users", ["username", "host", "password"],
|
||||
[Username, Host, Pass],
|
||||
["username='", Username ,"' and host='", Host, "'"])
|
||||
end).
|
||||
|
||||
add_user(LServer, Username, Pass) ->
|
||||
Host = escape(LServer),
|
||||
ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
["insert into users(username, password) "
|
||||
"values ('", Username, "', '", Pass, "');"]).
|
||||
["insert into users(username, host, password) "
|
||||
"values ('", Username, "', '", Host, "', '", Pass, "');"]).
|
||||
|
||||
del_user(LServer, Username) ->
|
||||
Host = escape(LServer),
|
||||
ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
["delete from users where username='", Username ,"';"]).
|
||||
["delete from users where username='", Username ,"' and host='", Host, "';"]).
|
||||
|
||||
del_user_return_password(_LServer, Username, Pass) ->
|
||||
P = ejabberd_odbc:sql_query_t(
|
||||
["select password from users where username='",
|
||||
Username, "';"]),
|
||||
del_user_return_password(LServer, Username, Pass) ->
|
||||
Host = escape(LServer),
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["select password from users where username='",
|
||||
Username, "' and host='", Host, "';"]),
|
||||
ejabberd_odbc:sql_query_t(["delete from users "
|
||||
"where username='", Username,
|
||||
"' and host='", Host,
|
||||
"' and password='", Pass, "';"]),
|
||||
P.
|
||||
Pass. % REVIEWME
|
||||
|
||||
list_users(LServer) ->
|
||||
Host = escape(LServer),
|
||||
ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
"select username from users").
|
||||
["select username from users where host='", Host, "'"]).
|
||||
|
||||
list_users(LServer, [{from, Start}, {to, End}]) when is_integer(Start) and
|
||||
is_integer(End) ->
|
||||
@ -211,6 +221,7 @@ list_users(LServer, [{prefix, Prefix},
|
||||
"limit ~w offset ~w ", [Prefix, Limit, Offset])).
|
||||
|
||||
users_number(LServer) ->
|
||||
Host = escape(LServer),
|
||||
case element(1, ejabberd_config:get_local_option({odbc_server, LServer})) of
|
||||
mysql ->
|
||||
ejabberd_odbc:sql_query(
|
||||
@ -224,13 +235,13 @@ users_number(LServer) ->
|
||||
"select reltuples from pg_class where oid = 'users'::regclass::oid");
|
||||
_ ->
|
||||
ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
"select count(*) from users")
|
||||
LServer,
|
||||
["select count(*) from users where host='", Host, "'"])
|
||||
end;
|
||||
_ ->
|
||||
ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
"select count(*) from users")
|
||||
LServer,
|
||||
["select count(*) from users where host='", Host, "'"])
|
||||
end.
|
||||
|
||||
users_number(LServer, [{prefix, Prefix}]) when is_list(Prefix) ->
|
||||
@ -243,10 +254,10 @@ users_number(LServer, [{prefix, Prefix}]) when is_list(Prefix) ->
|
||||
users_number(LServer, []) ->
|
||||
users_number(LServer).
|
||||
|
||||
|
||||
add_spool_sql(Username, XML) ->
|
||||
["insert into spool(username, xml) "
|
||||
"values ('", Username, "', '",
|
||||
add_spool_sql(LServer, Username, XML) ->
|
||||
Host = escape(LServer),
|
||||
["insert into spool(username, host, xml) "
|
||||
"values ('", Username, "', '", Host, "', '",
|
||||
XML,
|
||||
"');"].
|
||||
|
||||
@ -255,158 +266,177 @@ add_spool(LServer, Queries) ->
|
||||
LServer, Queries).
|
||||
|
||||
get_and_del_spool_msg_t(LServer, Username) ->
|
||||
Host = escape(LServer),
|
||||
F = fun() ->
|
||||
Result = ejabberd_odbc:sql_query_t(
|
||||
["select username, xml from spool where username='", Username, "'"
|
||||
" and host='", Host, "'"
|
||||
" order by seq;"]),
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["delete from spool where username='", Username, "';"]),
|
||||
["delete from spool where username='", Username, "' and host='", Host, "';"]),
|
||||
Result
|
||||
end,
|
||||
ejabberd_odbc:sql_transaction(LServer,F).
|
||||
|
||||
del_spool_msg(LServer, Username) ->
|
||||
Host = escape(LServer),
|
||||
ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
["delete from spool where username='", Username, "';"]).
|
||||
["delete from spool where username='", Username, "' and host='", Host, "';"]).
|
||||
|
||||
get_roster(LServer, Username) ->
|
||||
Host = escape(LServer),
|
||||
ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
["select username, jid, nick, subscription, ask, "
|
||||
"askmessage, server, subscribe, type from rosterusers "
|
||||
"where username='", Username, "'"]).
|
||||
"where username='", Username, "' and host='", Host, "'"]).
|
||||
|
||||
get_roster_jid_groups(LServer, Username) ->
|
||||
Host = escape(LServer),
|
||||
ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
["select jid, grp from rostergroups "
|
||||
"where username='", Username, "'"]).
|
||||
"where username='", Username, "' and host='", Host, "'"]).
|
||||
|
||||
get_roster_groups(_LServer, Username, SJID) ->
|
||||
get_roster_groups(LServer, Username, SJID) ->
|
||||
Host = escape(LServer),
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["select grp from rostergroups "
|
||||
"where username='", Username, "' "
|
||||
"where username='", Username, "' and host='", Host, "' "
|
||||
"and jid='", SJID, "';"]).
|
||||
|
||||
del_user_roster_t(LServer, Username) ->
|
||||
Host = escape(LServer),
|
||||
ejabberd_odbc:sql_transaction(
|
||||
LServer,
|
||||
fun() ->
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["delete from rosterusers "
|
||||
" where username='", Username, "';"]),
|
||||
" where username='", Username, "' and host='", Host, "';"]),
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["delete from rostergroups "
|
||||
" where username='", Username, "';"])
|
||||
" where username='", Username, "' and host='", Host, "';"])
|
||||
end).
|
||||
|
||||
get_roster_by_jid(_LServer, Username, SJID) ->
|
||||
get_roster_by_jid(LServer, Username, SJID) ->
|
||||
Host = escape(LServer),
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["select username, jid, nick, subscription, "
|
||||
"ask, askmessage, server, subscribe, type from rosterusers "
|
||||
"where username='", Username, "' "
|
||||
"where username='", Username, "' and host='", Host, "' "
|
||||
"and jid='", SJID, "';"]).
|
||||
|
||||
get_rostergroup_by_jid(LServer, Username, SJID) ->
|
||||
Host = escape(LServer),
|
||||
ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
["select grp from rostergroups "
|
||||
"where username='", Username, "' "
|
||||
"where username='", Username, "' and host='", Host, "' "
|
||||
"and jid='", SJID, "'"]).
|
||||
|
||||
del_roster(_LServer, Username, SJID) ->
|
||||
del_roster(LServer, Username, SJID) ->
|
||||
Host = escape(LServer),
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["delete from rosterusers "
|
||||
" where username='", Username, "' "
|
||||
" where username='", Username, "' and host='", Host, "' "
|
||||
" and jid='", SJID, "';"]),
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["delete from rostergroups "
|
||||
" where username='", Username, "' "
|
||||
" where username='", Username, "' and host='", Host, "' "
|
||||
" and jid='", SJID, "';"]).
|
||||
|
||||
del_roster_sql(Username, SJID) ->
|
||||
del_roster_sql(LServer, Username, SJID) ->
|
||||
Host = escape(LServer),
|
||||
[["delete from rosterusers "
|
||||
" where username='", Username, "' "
|
||||
" where username='", Username, "' and host='", Host, "' "
|
||||
" and jid='", SJID, "';"],
|
||||
["delete from rostergroups "
|
||||
" where username='", Username, "' "
|
||||
" where username='", Username, "' and host='", Host, "' "
|
||||
" and jid='", SJID, "';"]].
|
||||
|
||||
update_roster(_LServer, Username, SJID, ItemVals, ItemGroups) ->
|
||||
update_roster(LServer, Username, SJID, ItemVals, ItemGroups) ->
|
||||
Host = escape(LServer),
|
||||
update_t("rosterusers",
|
||||
["username", "jid", "nick", "subscription", "ask",
|
||||
["host", "username", "jid", "nick", "subscription", "ask",
|
||||
"askmessage", "server", "subscribe", "type"],
|
||||
ItemVals,
|
||||
["username='", Username, "' and jid='", SJID, "'"]),
|
||||
[Host | ItemVals],
|
||||
["username='", Username, "' and host='", Host, "' and jid='", SJID, "'"]),
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["delete from rostergroups "
|
||||
" where username='", Username, "' "
|
||||
" where username='", Username, "' and host='", Host, "' "
|
||||
" and jid='", SJID, "';"]),
|
||||
lists:foreach(fun(ItemGroup) ->
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["insert into rostergroups("
|
||||
" username, jid, grp) "
|
||||
" values ('", string:join(ItemGroup, "', '"), "');"])
|
||||
" host, username, jid, grp) "
|
||||
" values ('", Host, "', '", string:join(ItemGroup, "', '"), "');"])
|
||||
end,
|
||||
ItemGroups).
|
||||
|
||||
update_roster_sql(Username, SJID, ItemVals, ItemGroups) ->
|
||||
update_roster_sql(LServer, Username, SJID, ItemVals, ItemGroups) ->
|
||||
Host = escape(LServer),
|
||||
[["delete from rosterusers "
|
||||
" where username='", Username, "' "
|
||||
" where username='", Username, "' and host='", Host, "' "
|
||||
" and jid='", SJID, "';"],
|
||||
["insert into rosterusers("
|
||||
" username, jid, nick, "
|
||||
" host, username, jid, nick, "
|
||||
" subscription, ask, askmessage, "
|
||||
" server, subscribe, type) "
|
||||
" values ('", string:join(ItemVals, "', '"), "');"],
|
||||
" values ('", Host, "', '", string:join(ItemVals, "', '"), "');"],
|
||||
["delete from rostergroups "
|
||||
" where username='", Username, "' "
|
||||
" where username='", Username, "' and host='", Host, "' "
|
||||
" and jid='", SJID, "';"]] ++
|
||||
[["insert into rostergroups("
|
||||
" username, jid, grp) "
|
||||
" values ('", string:join(ItemGroup, "', '"), "');"] ||
|
||||
" host, username, jid, grp) "
|
||||
" values ('", Host, "', '", string:join(ItemGroup, "', '"), "');"] ||
|
||||
ItemGroup <- ItemGroups].
|
||||
|
||||
roster_subscribe(_LServer, Username, SJID, ItemVals) ->
|
||||
roster_subscribe(LServer, Username, SJID, ItemVals) ->
|
||||
Host = escape(LServer),
|
||||
update_t("rosterusers",
|
||||
["username", "jid", "nick", "subscription", "ask",
|
||||
["host", "username", "jid", "nick", "subscription", "ask",
|
||||
"askmessage", "server", "subscribe", "type"],
|
||||
ItemVals,
|
||||
["username='", Username, "' and jid='", SJID, "'"]).
|
||||
[Host | ItemVals],
|
||||
["username='", Username, "' and host='", Host, "' and jid='", SJID, "'"]).
|
||||
|
||||
get_subscription(LServer, Username, SJID) ->
|
||||
Host = escape(LServer),
|
||||
ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
["select subscription from rosterusers "
|
||||
"where username='", Username, "' "
|
||||
"where username='", Username, "' and host='", Host, "' "
|
||||
"and jid='", SJID, "'"]).
|
||||
|
||||
set_private_data(_LServer, Username, LXMLNS, SData) ->
|
||||
set_private_data(LServer, Username, LXMLNS, SData) ->
|
||||
Host = escape(LServer),
|
||||
update_t("private_storage",
|
||||
["username", "namespace", "data"],
|
||||
[Username, LXMLNS, SData],
|
||||
["username='", Username, "' and namespace='", LXMLNS, "'"]).
|
||||
["host", "username", "namespace", "data"],
|
||||
[Host, Username, LXMLNS, SData],
|
||||
["username='", Username, "' and host='", Host, "' and namespace='", LXMLNS, "'"]).
|
||||
|
||||
set_private_data_sql(Username, LXMLNS, SData) ->
|
||||
set_private_data_sql(LServer, Username, LXMLNS, SData) ->
|
||||
Host = escape(LServer),
|
||||
[["delete from private_storage "
|
||||
"where username='", Username, "' and "
|
||||
"where username='", Username, "' and host='", Host, "' and "
|
||||
"namespace='", LXMLNS, "';"],
|
||||
["insert into private_storage(username, namespace, data) "
|
||||
"values ('", Username, "', '", LXMLNS, "', "
|
||||
["insert into private_storage(host, username, namespace, data) "
|
||||
"values ('", Host, "', '", Username, "', '", LXMLNS, "', "
|
||||
"'", SData, "');"]].
|
||||
|
||||
get_private_data(LServer, Username, LXMLNS) ->
|
||||
Host = escape(LServer),
|
||||
ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
["select data from private_storage "
|
||||
"where username='", Username, "' and "
|
||||
"where username='", Username, "' and host='", Host, "' and "
|
||||
"namespace='", LXMLNS, "';"]).
|
||||
|
||||
del_user_private_storage(LServer, Username) ->
|
||||
Host = escape(LServer),
|
||||
ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
["delete from private_storage where username='", Username, "';"]).
|
||||
["delete from private_storage where username='", Username, "' and host='", Host, "';"]).
|
||||
|
||||
set_vcard(LServer, LUsername, SBDay, SCTRY, SEMail, SFN, SFamily, SGiven,
|
||||
SLBDay, SLCTRY, SLEMail, SLFN, SLFamily, SLGiven, SLLocality,
|
||||
@ -415,16 +445,16 @@ set_vcard(LServer, LUsername, SBDay, SCTRY, SEMail, SFN, SFamily, SGiven,
|
||||
ejabberd_odbc:sql_transaction(
|
||||
LServer,
|
||||
fun() ->
|
||||
update_t("vcard", ["username", "vcard"],
|
||||
[LUsername, SVCARD],
|
||||
["username='", LUsername, "'"]),
|
||||
update_t("vcard", ["host", "username", "vcard"],
|
||||
[LServer, LUsername, SVCARD],
|
||||
["username='", LUsername, "' and host='", LServer, "'"]),
|
||||
update_t("vcard_search",
|
||||
["username", "lusername", "fn", "lfn", "family",
|
||||
["host", "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,
|
||||
[LServer, Username, LUsername, SFN, SLFN, SFamily, SLFamily,
|
||||
SGiven, SLGiven, SMiddle, SLMiddle, SNickname,
|
||||
SLNickname, SBDay, SLBDay, SCTRY, SLCTRY,
|
||||
SLocality, SLLocality, SEMail, SLEMail, SOrgName,
|
||||
@ -436,7 +466,7 @@ get_vcard(LServer, Username) ->
|
||||
ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
["select vcard from vcard "
|
||||
"where username='", Username, "';"]).
|
||||
"where username='", Username, "' and host='", LServer, "';"]).
|
||||
|
||||
del_vcard(LServer, Username) ->
|
||||
ejabberd_odbc:sql_transaction(
|
||||
@ -457,34 +487,34 @@ get_default_privacy_list(LServer, Username) ->
|
||||
ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
["select name from privacy_default_list "
|
||||
"where username='", Username, "';"]).
|
||||
"where username='", Username, "' and host='", LServer, "';"]).
|
||||
|
||||
get_default_privacy_list_t(Username) ->
|
||||
get_default_privacy_list_t(LServer, Username) ->
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["select name from privacy_default_list "
|
||||
"where username='", Username, "';"]).
|
||||
"where username='", Username, "' and host='", LServer, "';"]).
|
||||
|
||||
get_privacy_list_names(LServer, Username) ->
|
||||
ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
["select name from privacy_list "
|
||||
"where username='", Username, "';"]).
|
||||
"where username='", Username, "' and host='", LServer, "';"]).
|
||||
|
||||
get_privacy_list_names_t(Username) ->
|
||||
get_privacy_list_names_t(LServer, Username) ->
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["select name from privacy_list "
|
||||
"where username='", Username, "';"]).
|
||||
"where username='", Username, "' and host='", LServer, "';"]).
|
||||
|
||||
get_privacy_list_id(LServer, Username, SName) ->
|
||||
ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
["select id from privacy_list "
|
||||
"where username='", Username, "' and name='", SName, "';"]).
|
||||
"where username='", Username, "' and name='", SName, "' and host='", LServer, "';"]).
|
||||
|
||||
get_privacy_list_id_t(Username, SName) ->
|
||||
get_privacy_list_id_t(LServer, Username, SName) ->
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["select id from privacy_list "
|
||||
"where username='", Username, "' and name='", SName, "';"]).
|
||||
"where username='", Username, "' and name='", SName, "' and host='", LServer, "';"]).
|
||||
|
||||
get_privacy_list_data(LServer, Username, SName) ->
|
||||
ejabberd_odbc:sql_query(
|
||||
@ -493,7 +523,7 @@ get_privacy_list_data(LServer, Username, SName) ->
|
||||
"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, "') "
|
||||
" username='", Username, "' and name='", SName, "' and host='", LServer, "') "
|
||||
"order by ord;"]).
|
||||
|
||||
get_privacy_list_data_by_id(LServer, ID) ->
|
||||
@ -504,25 +534,26 @@ get_privacy_list_data_by_id(LServer, ID) ->
|
||||
"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, "'"]).
|
||||
set_default_privacy_list(LServer, Username, SName) ->
|
||||
update_t("privacy_default_list", ["host", "username", "name"],
|
||||
[LServer, Username, SName],
|
||||
["host='", LServer, "' and username='", Username, "'"]).
|
||||
|
||||
unset_default_privacy_list(LServer, Username) ->
|
||||
ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
["delete from privacy_default_list "
|
||||
" where username='", Username, "';"]).
|
||||
" where username='", Username, "' and host='", LServer, "';"]).
|
||||
|
||||
remove_privacy_list(Username, SName) ->
|
||||
remove_privacy_list(LServer, Username, SName) ->
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["delete from privacy_list "
|
||||
"where username='", Username, "' and name='", SName, "';"]).
|
||||
"where username='", Username, "' and name='", SName, "' and host='", LServer, "';"]).
|
||||
|
||||
add_privacy_list(Username, SName) ->
|
||||
add_privacy_list(LServer, Username, SName) ->
|
||||
ejabberd_odbc:sql_query_t(
|
||||
["insert into privacy_list(username, name) "
|
||||
"values ('", Username, "', '", SName, "');"]).
|
||||
["insert into privacy_list(host, username, name) "
|
||||
"values ('", LServer, "', '", Username, "', '", SName, "');"]).
|
||||
|
||||
set_privacy_list(ID, RItems) ->
|
||||
ejabberd_odbc:sql_query_t(
|
||||
@ -542,13 +573,13 @@ set_privacy_list(ID, RItems) ->
|
||||
del_privacy_lists(LServer, Server, Username) ->
|
||||
ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
["delete from privacy_list where username='", Username, "';"]),
|
||||
["delete from privacy_list where username='", Username, "' and host='", LServer, "';"]),
|
||||
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, "';"]).
|
||||
["delete from privacy_default_list where username='", Username, "' and host='", LServer, "';"]).
|
||||
|
||||
%% Characters to escape
|
||||
escape($\0) -> "\\0";
|
||||
|
@ -18,21 +18,24 @@
|
||||
--
|
||||
|
||||
CREATE TABLE users (
|
||||
username text PRIMARY KEY,
|
||||
username text NOT NULL,
|
||||
host text NOT NULL,
|
||||
"password" text NOT NULL,
|
||||
PRIMARY KEY (host, username)
|
||||
created_at TIMESTAMP NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE last (
|
||||
username text PRIMARY KEY,
|
||||
username text NOT NULL,
|
||||
host text NOT NULL,
|
||||
seconds text NOT NULL,
|
||||
state text NOT NULL
|
||||
state text NOT NULL,
|
||||
PRIMARY KEY (host, username)
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE rosterusers (
|
||||
username text NOT NULL,
|
||||
host text NOT NULL,
|
||||
jid text NOT NULL,
|
||||
nick text NOT NULL,
|
||||
subscription character(1) NOT NULL,
|
||||
@ -41,42 +44,50 @@ CREATE TABLE rosterusers (
|
||||
server character(1) NOT NULL,
|
||||
subscribe text,
|
||||
"type" text,
|
||||
<<<<<<< HEAD
|
||||
PRIMARY KEY (host, username, jid)
|
||||
=======
|
||||
created_at TIMESTAMP NOT NULL DEFAULT now()
|
||||
>>>>>>> 30
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX i_rosteru_user_jid ON rosterusers USING btree (username, jid);
|
||||
CREATE INDEX i_rosteru_username ON rosterusers USING btree (username);
|
||||
CREATE INDEX i_rosteru_jid ON rosterusers USING btree (jid);
|
||||
|
||||
|
||||
CREATE TABLE rostergroups (
|
||||
username text NOT NULL,
|
||||
host text NOT NULL,
|
||||
jid text NOT NULL,
|
||||
grp text NOT NULL
|
||||
grp text NOT NULL,
|
||||
PRIMARY KEY (host, username, jid)
|
||||
);
|
||||
|
||||
CREATE INDEX pk_rosterg_user_jid ON rostergroups USING btree (username, jid);
|
||||
|
||||
|
||||
CREATE TABLE spool (
|
||||
username text NOT NULL,
|
||||
host text NOT NULL,
|
||||
xml text NOT NULL,
|
||||
seq SERIAL,
|
||||
<<<<<<< HEAD
|
||||
PRIMARY KEY (host, username, seq)
|
||||
=======
|
||||
created_at TIMESTAMP NOT NULL DEFAULT now()
|
||||
>>>>>>> 30
|
||||
);
|
||||
|
||||
CREATE INDEX i_despool ON spool USING btree (username);
|
||||
|
||||
|
||||
CREATE TABLE vcard (
|
||||
<<<<<<< HEAD
|
||||
username text NOT NULL,
|
||||
host text NOT NULL,
|
||||
vcard text NOT NULL,
|
||||
PRIMARY KEY (host, username)
|
||||
=======
|
||||
username text PRIMARY KEY,
|
||||
vcard text NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT now()
|
||||
>>>>>>> 30
|
||||
);
|
||||
|
||||
CREATE TABLE vcard_search (
|
||||
host text NOT NULL,
|
||||
username text NOT NULL,
|
||||
lusername text PRIMARY KEY,
|
||||
lusername text NOT NULL,
|
||||
fn text NOT NULL,
|
||||
lfn text NOT NULL,
|
||||
family text NOT NULL,
|
||||
@ -98,9 +109,11 @@ CREATE TABLE vcard_search (
|
||||
orgname text NOT NULL,
|
||||
lorgname text NOT NULL,
|
||||
orgunit text NOT NULL,
|
||||
lorgunit text NOT NULL
|
||||
lorgunit text NOT NULL,
|
||||
PRIMARY KEY (host, lusername)
|
||||
);
|
||||
|
||||
CREATE INDEX i_vcard_search_lusername ON vcard_search(lusername);
|
||||
CREATE INDEX i_vcard_search_lfn ON vcard_search(lfn);
|
||||
CREATE INDEX i_vcard_search_lfamily ON vcard_search(lfamily);
|
||||
CREATE INDEX i_vcard_search_lgiven ON vcard_search(lgiven);
|
||||
@ -114,20 +127,24 @@ CREATE INDEX i_vcard_search_lorgname ON vcard_search(lorgname);
|
||||
CREATE INDEX i_vcard_search_lorgunit ON vcard_search(lorgunit);
|
||||
|
||||
CREATE TABLE privacy_default_list (
|
||||
username text PRIMARY KEY,
|
||||
name text NOT NULL
|
||||
username text NOT NULL,
|
||||
host text NOT NULL,
|
||||
name text NOT NULL,
|
||||
PRIMARY KEY (host, username)
|
||||
);
|
||||
|
||||
CREATE TABLE privacy_list (
|
||||
username text NOT NULL,
|
||||
host text NOT NULL,
|
||||
name text NOT NULL,
|
||||
id SERIAL UNIQUE,
|
||||
<<<<<<< HEAD
|
||||
PRIMARY KEY (host, username, name)
|
||||
=======
|
||||
created_at TIMESTAMP NOT NULL DEFAULT now()
|
||||
>>>>>>> 30
|
||||
);
|
||||
|
||||
CREATE INDEX i_privacy_list_username ON privacy_list USING btree (username);
|
||||
CREATE UNIQUE INDEX i_privacy_list_username_name ON privacy_list USING btree (username, name);
|
||||
|
||||
CREATE TABLE privacy_list_data (
|
||||
id bigint REFERENCES privacy_list(id) ON DELETE CASCADE,
|
||||
t character(1) NOT NULL,
|
||||
@ -138,18 +155,28 @@ CREATE TABLE privacy_list_data (
|
||||
match_iq boolean NOT NULL,
|
||||
match_message boolean NOT NULL,
|
||||
match_presence_in boolean NOT NULL,
|
||||
match_presence_out boolean NOT NULL
|
||||
match_presence_out boolean NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE private_storage (
|
||||
username text NOT NULL,
|
||||
host text NOT NULL,
|
||||
namespace text NOT NULL,
|
||||
data text NOT NULL,
|
||||
<<<<<<< HEAD
|
||||
PRIMARY KEY (host, username, namespace)
|
||||
=======
|
||||
created_at TIMESTAMP NOT NULL DEFAULT now()
|
||||
>>>>>>> 30
|
||||
);
|
||||
|
||||
CREATE INDEX i_private_storage_username ON private_storage USING btree (username);
|
||||
CREATE UNIQUE INDEX i_private_storage_username_namespace ON private_storage USING btree (username, namespace);
|
||||
CREATE TABLE hosts (
|
||||
clusterid integer NOT NULL,
|
||||
host text NOT NULL,
|
||||
config text NOT NULL,
|
||||
PRIMARY KEY (host)
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE roster_version (
|
||||
|
@ -33,7 +33,12 @@
|
||||
|
||||
|
||||
start() ->
|
||||
register(random_generator, spawn(randoms, init, [])).
|
||||
case erlang:whereis(random_generator) of
|
||||
Pid when is_pid(Pid) ->
|
||||
true;
|
||||
undefined ->
|
||||
register(random_generator, spawn(randoms, init, []))
|
||||
end.
|
||||
|
||||
init() ->
|
||||
{A1, A2, A3} = now(),
|
||||
|
@ -165,7 +165,7 @@ process(["doc", LocalFile], _Request) ->
|
||||
|
||||
process(["server", SHost | RPath] = Path, #request{auth = Auth, lang = Lang, host = HostHTTP, method = Method} = Request) ->
|
||||
Host = exmpp_stringprep:nameprep(SHost),
|
||||
case lists:member(Host, ?MYHOSTS) of
|
||||
case ?IS_MY_HOST(Host) of
|
||||
true ->
|
||||
case get_auth_admin(Auth, HostHTTP, Path, Method) of
|
||||
{ok, {User, Server}} ->
|
||||
|
Loading…
Reference in New Issue
Block a user