diff options
author | Alexey Shchepin <alexey@process-one.net> | 2005-06-20 07:18:13 +0400 |
---|---|---|
committer | Alexey Shchepin <alexey@process-one.net> | 2005-06-20 07:18:13 +0400 |
commit | 4098c3ecbae91929039410ddf45f400b6e87db39 (patch) | |
tree | 752f096271a724d865377e34d896529229756808 | |
parent | cb9007532739a81cf4e29b6134ea6eaaf6c5f353 (diff) |
* (all): Enhanced virtual hosting support
SVN Revision: 370
41 files changed, 1039 insertions, 747 deletions
@@ -1,3 +1,7 @@ +2005-06-20 Alexey Shchepin <alexey@sevcom.net> + + * (all): Enhanced virtual hosting support + 2005-05-28 Alexey Shchepin <alexey@sevcom.net> * src/web/ejabberd_web_admin.erl: Bugfix diff --git a/src/acl.erl b/src/acl.erl index 67b928cd1..c7ffb874c 100644 --- a/src/acl.erl +++ b/src/acl.erl @@ -11,12 +11,12 @@ -vsn('$Revision$ '). -export([start/0, - to_record/2, - add/2, - add_list/2, - match_rule/2, + to_record/3, + add/3, + add_list/3, + match_rule/3, % for debugging only - match_acl/2]). + match_acl/3]). -include("ejabberd.hrl"). @@ -30,30 +30,35 @@ start() -> mnesia:add_table_copy(acl, node(), ram_copies), ok. -to_record(ACLName, ACLSpec) -> - #acl{aclname = ACLName, aclspec = ACLSpec}. +to_record(Host, ACLName, ACLSpec) -> + #acl{aclname = {ACLName, Host}, aclspec = ACLSpec}. -add(ACLName, ACLSpec) -> +add(Host, ACLName, ACLSpec) -> F = fun() -> - mnesia:write(#acl{aclname = ACLName, aclspec = ACLSpec}) + mnesia:write(#acl{aclname = {ACLName, Host}, + aclspec = ACLSpec}) end, mnesia:transaction(F). -add_list(ACLs, Clear) -> +add_list(Host, ACLs, Clear) -> F = fun() -> if Clear -> - Ks = mnesia:all_keys(acl), + Ks = mnesia:select( + acl, [{{acl, {'$1', Host}, '$2'}, [], ['$1']}]), lists:foreach(fun(K) -> - mnesia:delete({acl, K}) + mnesia:delete({acl, {K, Host}}) end, Ks); true -> ok end, lists:foreach(fun(ACL) -> case ACL of - #acl{} -> - mnesia:write(ACL) + #acl{aclname = ACLName, + aclspec = ACLSpec} -> + mnesia:write( + #acl{aclname = {ACLName, Host}, + aclspec = ACLSpec}) end end, ACLs) end, @@ -66,30 +71,53 @@ add_list(ACLs, Clear) -> -match_rule(Rule, JID) -> +match_rule(global, Rule, JID) -> case Rule of all -> allow; none -> deny; _ -> - case ejabberd_config:get_global_option({access, Rule}) of + case ejabberd_config:get_global_option({access, Rule, global}) of undefined -> deny; - ACLs -> - match_acls(ACLs, JID) + GACLs -> + match_acls(GACLs, JID, global) + end + end; + +match_rule(Host, Rule, JID) -> + case Rule of + all -> allow; + none -> deny; + _ -> + case ejabberd_config:get_global_option({access, Rule, global}) of + undefined -> + case ejabberd_config:get_global_option({access, Rule, Host}) of + undefined -> + deny; + ACLs -> + match_acls(ACLs, JID, Host) + end; + GACLs -> + case ejabberd_config:get_global_option({access, Rule, Host}) of + undefined -> + match_acls(GACLs, JID, Host); + ACLs -> + match_acls(GACLs ++ ACLs, JID, Host) + end end end. -match_acls([], _) -> +match_acls([], _, Host) -> deny; -match_acls([{Access, ACL} | ACLs], JID) -> - case match_acl(ACL, JID) of +match_acls([{Access, ACL} | ACLs], JID, Host) -> + case match_acl(ACL, JID, Host) of true -> Access; _ -> - match_acls(ACLs, JID) + match_acls(ACLs, JID, Host) end. -match_acl(ACL, JID) -> +match_acl(ACL, JID, Host) -> case ACL of all -> true; none -> false; @@ -100,14 +128,20 @@ match_acl(ACL, JID) -> all -> true; {user, U} -> - (U == User) andalso (?MYNAME == Server); + (U == User) + andalso + ((Host == Server) orelse + ((Host == global) andalso + lists:member(Server, ?MYHOSTS))); {user, U, S} -> (U == User) andalso (S == Server); {server, S} -> S == Server; {user_regexp, UR} -> - (?MYNAME == Server) andalso - is_regexp_match(User, UR); + ((Host == Server) orelse + ((Host == global) andalso + lists:member(Server, ?MYHOSTS))) + andalso is_regexp_match(User, UR); {user_regexp, UR, S} -> (S == Server) andalso is_regexp_match(User, UR); @@ -117,7 +151,10 @@ match_acl(ACL, JID) -> is_regexp_match(Server, SR) andalso is_regexp_match(User, UR); {user_glob, UR} -> - (?MYNAME == Server) andalso + ((Host == Server) orelse + ((Host == global) andalso + lists:member(Server, ?MYHOSTS))) + andalso is_glob_match(User, UR); {user_glob, UR, S} -> (S == Server) andalso @@ -128,7 +165,9 @@ match_acl(ACL, JID) -> is_glob_match(Server, SR) andalso is_glob_match(User, UR) end - end, ets:lookup(acl, ACL)) + end, + ets:lookup(acl, {ACL, global}) ++ + ets:lookup(acl, {ACL, Host})) end. is_regexp_match(String, RegExp) -> diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl index 26b29f4b6..84aec2d25 100644 --- a/src/ejabberd_app.erl +++ b/src/ejabberd_app.erl @@ -87,14 +87,18 @@ db_init() -> mnesia:wait_for_tables(mnesia:system_info(local_tables), infinity). load_modules() -> - case ejabberd_config:get_local_option(modules) of - undefined -> - ok; - Modules -> - lists:foreach(fun({Module, Args}) -> - gen_mod:start_module(Module, Args) - end, Modules) - end. + lists:foreach( + fun(Host) -> + case ejabberd_config:get_local_option(modules) of + undefined -> + ok; + Modules -> + lists:foreach( + fun({Module, Args}) -> + gen_mod:start_module(Host, Module, Args) + end, Modules) + end + end, ?MYHOSTS). dump_ports() -> diff --git a/src/ejabberd_auth_internal.erl b/src/ejabberd_auth_internal.erl index 8dbd58818..bce5460a0 100644 --- a/src/ejabberd_auth_internal.erl +++ b/src/ejabberd_auth_internal.erl @@ -165,7 +165,7 @@ remove_user(User, Server) -> mnesia:delete({passwd, US}) end, mnesia:transaction(F), - ejabberd_hooks:run(remove_user, [User, Server]). + ejabberd_hooks:run(remove_user, LServer, [User, Server]). remove_user(User, Server, Password) -> LUser = jlib:nodeprep(User), @@ -184,7 +184,7 @@ remove_user(User, Server, Password) -> end, case mnesia:transaction(F) of {atomic, ok} -> - ejabberd_hooks:run(remove_user, [User, Server]), + ejabberd_hooks:run(remove_user, LServer, [User, Server]), ok; {atomic, Res} -> Res; diff --git a/src/ejabberd_auth_odbc.erl b/src/ejabberd_auth_odbc.erl index 67696ed13..33e084476 100644 --- a/src/ejabberd_auth_odbc.erl +++ b/src/ejabberd_auth_odbc.erl @@ -170,7 +170,7 @@ is_user_exists(User, _Server) -> end end. -remove_user(User, _Server) -> +remove_user(User, Server) -> case jlib:nodeprep(User) of error -> error; @@ -178,10 +178,10 @@ remove_user(User, _Server) -> Username = ejabberd_odbc:escape(LUser), catch ejabberd_odbc:sql_query( ["delete from users where username='", Username ,"'"]), - ejabberd_hooks:run(remove_user, [User]) + ejabberd_hooks:run(remove_user, jlib:nameprep(Server), [User]) end. -remove_user(User, _Server, Password) -> +remove_user(User, Server, Password) -> case jlib:nodeprep(User) of error -> error; @@ -196,7 +196,8 @@ remove_user(User, _Server, Password) -> "where username='", Username, "' and password='", Pass, "';" "commit"]) of {selected, ["password"], [{Password}]} -> - ejabberd_hooks:run(remove_user, [User]), + ejabberd_hooks:run(remove_user, jlib:nameprep(Server), + [User]), ok; {selected, ["password"], []} -> not_exists; diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 361751f66..4a88e048c 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -340,7 +340,8 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> {auth, _ID, set, {U, P, D, R}} -> JID = jlib:make_jid(U, StateData#state.server, R), case (JID /= error) andalso - (acl:match_rule(StateData#state.access, JID) == allow) of + (acl:match_rule(StateData#state.server, + StateData#state.access, JID) == allow) of true -> case ejabberd_auth:check_password( U, StateData#state.server, P, @@ -358,6 +359,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> change_shaper(StateData, JID), {Fs, Ts} = ejabberd_hooks:run_fold( roster_get_subscription_lists, + StateData#state.server, {[], []}, [U, StateData#state.server]), LJID = jlib:jid_tolower( @@ -651,7 +653,8 @@ wait_for_session({xmlstreamelement, El}, StateData) -> U = StateData#state.user, R = StateData#state.resource, JID = StateData#state.jid, - case acl:match_rule(StateData#state.access, JID) of + case acl:match_rule(StateData#state.server, + StateData#state.access, JID) of allow -> ?INFO_MSG("(~w) Opened session for ~s", [StateData#state.socket, @@ -663,6 +666,7 @@ wait_for_session({xmlstreamelement, El}, StateData) -> change_shaper(StateData, JID), {Fs, Ts} = ejabberd_hooks:run_fold( roster_get_subscription_lists, + StateData#state.server, {[], []}, [U, StateData#state.server]), LJID = jlib:jid_tolower(jlib:jid_remove_resource(JID)), @@ -764,6 +768,7 @@ session_established({xmlstreamelement, El}, StateData) -> _ -> ejabberd_hooks:run( user_send_packet, + Server, [FromJID, ToJID, NewEl]), ejabberd_router:route( FromJID, ToJID, NewEl), @@ -772,6 +777,7 @@ session_established({xmlstreamelement, El}, StateData) -> end; "message" -> ejabberd_hooks:run(user_send_packet, + Server, [FromJID, ToJID, NewEl]), ejabberd_router:route(FromJID, ToJID, NewEl), StateData; @@ -983,6 +989,7 @@ handle_info({route, From, To, Packet}, StateName, StateData) -> Text = xml:element_to_string(FixedPacket), send_text(StateData, Text), ejabberd_hooks:run(user_receive_packet, + StateData#state.server, [StateData#state.jid, From, To, FixedPacket]), {next_state, StateName, NewState}; true -> @@ -1055,7 +1062,8 @@ terminate(_Reason, StateName, StateData) -> %%%---------------------------------------------------------------------- change_shaper(StateData, JID) -> - Shaper = acl:match_rule(StateData#state.shaper, JID), + Shaper = acl:match_rule(StateData#state.server, + StateData#state.shaper, JID), ejabberd_receiver:change_shaper(StateData#state.receiver, Shaper). send_text(StateData, Text) -> @@ -1208,6 +1216,7 @@ presence_update(From, Packet, StateData) -> if FromUnavail -> ejabberd_hooks:run(user_available_hook, + StateData#state.server, [StateData#state.jid]), resend_offline_messages(StateData), presence_broadcast_first( @@ -1248,21 +1257,25 @@ presence_track(From, To, Packet, StateData) -> "subscribe" -> ejabberd_router:route(jlib:jid_remove_resource(From), To, Packet), ejabberd_hooks:run(roster_out_subscription, + Server, [User, Server, To, subscribe]), StateData; "subscribed" -> ejabberd_router:route(jlib:jid_remove_resource(From), To, Packet), ejabberd_hooks:run(roster_out_subscription, + Server, [User, Server, To, subscribed]), StateData; "unsubscribe" -> ejabberd_router:route(jlib:jid_remove_resource(From), To, Packet), ejabberd_hooks:run(roster_out_subscription, + Server, [User, Server, To, unsubscribe]), StateData; "unsubscribed" -> ejabberd_router:route(jlib:jid_remove_resource(From), To, Packet), ejabberd_hooks:run(roster_out_subscription, + Server, [User, Server, To, unsubscribed]), StateData; "error" -> @@ -1505,7 +1518,9 @@ process_privacy_iq(From, To, resend_offline_messages(#state{user = User, server = Server, privacy_list = PrivList} = StateData) -> - case ejabberd_hooks:run_fold(resend_offline_messages_hook, [], + case ejabberd_hooks:run_fold(resend_offline_messages_hook, + Server, + [], [User, Server]) of Rs when list(Rs) -> lists:foreach( diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index e1aa9c2df..2f7c8bb0e 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -1,7 +1,7 @@ %%%---------------------------------------------------------------------- %%% File : ejabberd_config.erl %%% Author : Alexey Shchepin <alexey@sevcom.net> -%%% Purpose : +%%% Purpose : Load config file %%% Created : 14 Dec 2002 by Alexey Shchepin <alexey@sevcom.net> %%% Id : $Id$ %%%---------------------------------------------------------------------- @@ -19,12 +19,12 @@ -record(config, {key, value}). -record(local_config, {key, value}). -record(state, {opts = [], + hosts = [], override_local = false, override_global = false, override_acls = false}). start() -> - %ets:new(ejabberd_config, [named_table, public]), mnesia:create_table(config, [{disc_copies, [node()]}, {attributes, record_info(fields, config)}]), @@ -34,8 +34,6 @@ start() -> {local_content, true}, {attributes, record_info(fields, local_config)}]), mnesia:add_table_copy(local_config, node(), ram_copies), - - %% mremond: Config file can be configured from the command line Config = case application:get_env(config) of {ok, Path} -> Path; undefined -> @@ -52,13 +50,38 @@ start() -> load_file(File) -> case file:consult(File) of {ok, Terms} -> - Res = lists:foldl(fun process_term/2, #state{}, Terms), + State = lists:foldl(fun search_hosts/2, #state{}, Terms), + Res = lists:foldl(fun process_term/2, State, Terms), set_opts(Res); {error, Reason} -> ?ERROR_MSG("Can't load config file ~p: ~p", [File, Reason]), exit(file:format_error(Reason)) end. +search_hosts(Term, State) -> + case Term of + {host, Host} -> + if + State#state.hosts == [] -> + add_option(hosts, [Host], State#state{hosts = [Host]}); + true -> + ?ERROR_MSG("Can't load config file: " + "too many hosts definitions", []), + exit("too many hosts definitions") + end; + {hosts, Hosts} -> + if + State#state.hosts == [] -> + add_option(hosts, Hosts, State#state{hosts = Hosts}); + true -> + ?ERROR_MSG("Can't load config file: " + "too many hosts definitions", []), + exit("too many hosts definitions") + end; + _ -> + State + end. + process_term(Term, State) -> case Term of override_global -> @@ -68,20 +91,40 @@ process_term(Term, State) -> override_acls -> State#state{override_acls = true}; {acl, ACLName, ACLData} -> + process_host_term(Term, global, State); + {access, RuleName, Rules} -> + process_host_term(Term, global, State); + {shaper, Name, Data} -> + lists:foldl(fun(Host, S) -> process_host_term(Term, Host, S) end, + State, State#state.hosts); + {host, Host} -> + State; + {hosts, Hosts} -> + State; + {Opt, Val} -> + lists:foldl(fun(Host, S) -> process_host_term(Term, Host, S) end, + State, State#state.hosts) + end. + +process_host_term(Term, Host, State) -> + case Term of + {acl, ACLName, ACLData} -> State#state{opts = - [acl:to_record(ACLName, ACLData) | State#state.opts]}; + [acl:to_record(Host, ACLName, ACLData) | State#state.opts]}; {access, RuleName, Rules} -> - State#state{opts = [#config{key = {access, RuleName}, + State#state{opts = [#config{key = {access, RuleName, Host}, value = Rules} | State#state.opts]}; {shaper, Name, Data} -> - State#state{opts = [#config{key = {shaper, Name}, + State#state{opts = [#config{key = {shaper, Name, Host}, value = Data} | State#state.opts]}; {host, Host} -> - add_option(hosts, [Host], State); + State; + {hosts, Hosts} -> + State; {Opt, Val} -> - add_option(Opt, Val, State) + add_option({Opt, Host}, Val, State) end. add_option(Opt, Val, State) -> diff --git a/src/ejabberd_hooks.erl b/src/ejabberd_hooks.erl index d316fae89..1888dabd3 100644 --- a/src/ejabberd_hooks.erl +++ b/src/ejabberd_hooks.erl @@ -16,7 +16,11 @@ add/4, delete/4, run/2, - run_fold/3]). + run_fold/3, + add/5, + delete/5, + run/3, + run_fold/4]). %% gen_server callbacks -export([init/1, @@ -37,13 +41,22 @@ start_link() -> gen_server:start_link({local, ejabberd_hooks}, ejabberd_hooks, [], []). add(Hook, Module, Function, Seq) -> - gen_server:call(ejabberd_hooks, {add, Hook, Module, Function, Seq}). + add(Hook, global, Module, Function, Seq). + +add(Hook, Host, Module, Function, Seq) -> + gen_server:call(ejabberd_hooks, {add, Hook, Host, Module, Function, Seq}). delete(Hook, Module, Function, Seq) -> - gen_server:call(ejabberd_hooks, {delete, Hook, Module, Function, Seq}). + delete(Hook, global, Module, Function, Seq). + +delete(Hook, Host, Module, Function, Seq) -> + gen_server:call(ejabberd_hooks, {delete, Hook, Host, Module, Function, Seq}). run(Hook, Args) -> - case ets:lookup(hooks, Hook) of + run(Hook, global, Args). + +run(Hook, Host, Args) -> + case ets:lookup(hooks, {Hook, Host}) of [{_, Ls}] -> run1(Ls, Hook, Args); [] -> @@ -51,7 +64,10 @@ run(Hook, Args) -> end. run_fold(Hook, Val, Args) -> - case ets:lookup(hooks, Hook) of + run_fold(Hook, global, Val, Args). + +run_fold(Hook, Host, Val, Args) -> + case ets:lookup(hooks, {Hook, Host}) of [{_, Ls}] -> run_fold1(Ls, Hook, Val, Args); [] -> @@ -82,8 +98,8 @@ init([]) -> %% {stop, Reason, Reply, State} | (terminate/2 is called) %% {stop, Reason, State} (terminate/2 is called) %%---------------------------------------------------------------------- -handle_call({add, Hook, Module, Function, Seq}, From, State) -> - Reply = case ets:lookup(hooks, Hook) of +handle_call({add, Hook, Host, Module, Function, Seq}, From, State) -> + Reply = case ets:lookup(hooks, {Hook, Host}) of [{_, Ls}] -> El = {Seq, Module, Function}, case lists:member(El, Ls) of @@ -91,20 +107,20 @@ handle_call({add, Hook, Module, Function, Seq}, From, State) -> ok; false -> NewLs = lists:merge(Ls, [El]), - ets:insert(hooks, {Hook, NewLs}), + ets:insert(hooks, {{Hook, Host}, NewLs}), ok end; [] -> NewLs = [{Seq, Module, Function}], - ets:insert(hooks, {Hook, NewLs}), + ets:insert(hooks, {{Hook, Host}, NewLs}), ok end, {reply, Reply, State}; -handle_call({delete, Hook, Module, Function, Seq}, From, State) -> - Reply = case ets:lookup(hooks, Hook) of +handle_call({delete, Hook, Host, Module, Function, Seq}, From, State) -> + Reply = case ets:lookup(hooks, {Hook, Host}) of [{_, Ls}] -> NewLs = lists:delete({Seq, Module, Function}, Ls), - ets:insert(hooks, {Hook, NewLs}), + ets:insert(hooks, {{Hook, Host}, NewLs}), ok; [] -> ok diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index 3e7eaf1b9..a9fa5ee2e 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -13,9 +13,9 @@ -export([start_link/0, init/0]). -export([route/3, - register_iq_handler/3, register_iq_handler/4, - unregister_iq_handler/1, + register_iq_handler/5, + unregister_iq_handler/2, refresh_iq_handlers/0, bounce_resource_packet/3 ]). @@ -33,11 +33,11 @@ start_link() -> init() -> lists:foreach( fun(Host) -> - ejabberd_router:register_route(Host, {apply, ?MODULE, route}) + ejabberd_router:register_route(Host, {apply, ?MODULE, route}), + ejabberd_hooks:add(local_send_to_resource_hook, Host, + ?MODULE, bounce_resource_packet, 100) end, ?MYHOSTS), catch ets:new(?IQTABLE, [named_table, public]), - ejabberd_hooks:add(local_send_to_resource_hook, - ?MODULE, bounce_resource_packet, 100), loop(). loop() -> @@ -51,32 +51,32 @@ loop() -> ok end, loop(); - {register_iq_handler, XMLNS, Module, Function} -> - ets:insert(?IQTABLE, {XMLNS, Module, Function}), - catch mod_disco:register_feature(XMLNS), + {register_iq_handler, Host, XMLNS, Module, Function} -> + ets:insert(?IQTABLE, {{XMLNS, Host}, Module, Function}), + catch mod_disco:register_feature(Host, XMLNS), loop(); - {register_iq_handler, XMLNS, Module, Function, Opts} -> - ets:insert(?IQTABLE, {XMLNS, Module, Function, Opts}), - catch mod_disco:register_feature(XMLNS), + {register_iq_handler, Host, XMLNS, Module, Function, Opts} -> + ets:insert(?IQTABLE, {{XMLNS, Host}, Module, Function, Opts}), + catch mod_disco:register_feature(Host, XMLNS), loop(); - {unregister_iq_handler, XMLNS} -> - case ets:lookup(?IQTABLE, XMLNS) of + {unregister_iq_handler, Host, XMLNS} -> + case ets:lookup(?IQTABLE, {XMLNS, Host}) of [{_, Module, Function, Opts}] -> gen_iq_handler:stop_iq_handler(Module, Function, Opts); _ -> ok end, - ets:delete(?IQTABLE, XMLNS), - catch mod_disco:unregister_feature(XMLNS), + ets:delete(?IQTABLE, {XMLNS, Host}), + catch mod_disco:unregister_feature(Host, XMLNS), loop(); refresh_iq_handlers -> lists:foreach( fun(T) -> case T of - {XMLNS, _Module, _Function, _Opts} -> - catch mod_disco:register_feature(XMLNS); - {XMLNS, _Module, _Function} -> - catch mod_disco:register_feature(XMLNS); + {{XMLNS, Host}, _Module, _Function, _Opts} -> + catch mod_disco:register_feature(Host, XMLNS); + {{XMLNS, Host}, _Module, _Function} -> + catch mod_disco:register_feature(Host, XMLNS); _ -> ok end @@ -112,6 +112,7 @@ do_route(From, To, Packet) -> "result" -> ok; _ -> ejabberd_hooks:run(local_send_to_resource_hook, + To#jid.lserver, [From, To, Packet]) end end. @@ -120,7 +121,8 @@ process_iq(From, To, Packet) -> IQ = jlib:iq_query_info(Packet), case IQ of #iq{xmlns = XMLNS} -> - case ets:lookup(?IQTABLE, XMLNS) of + Host = To#jid.lserver, + case ets:lookup(?IQTABLE, {XMLNS, Host}) of [{_, Module, Function}] -> ResIQ = Module:Function(From, To, IQ), if @@ -131,7 +133,7 @@ process_iq(From, To, Packet) -> ok end; [{_, Module, Function, Opts}] -> - gen_iq_handler:handle(Module, Function, Opts, + gen_iq_handler:handle(Host, Module, Function, Opts, From, To, IQ); [] -> Err = jlib:make_error_reply( @@ -155,14 +157,14 @@ route(From, To, Packet) -> ok end. -register_iq_handler(XMLNS, Module, Fun) -> - ejabberd_local ! {register_iq_handler, XMLNS, Module, Fun}. +register_iq_handler(Host, XMLNS, Module, Fun) -> + ejabberd_local ! {register_iq_handler, Host, XMLNS, Module, Fun}. -register_iq_handler(XMLNS, Module, Fun, Opts) -> - ejabberd_local ! {register_iq_handler, XMLNS, Module, Fun, Opts}. +register_iq_handler(Host, XMLNS, Module, Fun, Opts) -> + ejabberd_local ! {register_iq_handler, Host, XMLNS, Module, Fun, Opts}. -unregister_iq_handler(XMLNS) -> - ejabberd_local ! {unregister_iq_handler, XMLNS}. +unregister_iq_handler(Host, XMLNS) -> + ejabberd_local ! {unregister_iq_handler, Host, XMLNS}. refresh_iq_handlers() -> ejabberd_local ! refresh_iq_handlers. diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 5373123f1..1c09c0607 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -148,7 +148,7 @@ stream_established({xmlstreamelement, El}, StateData) -> Key, StateData#state.streamid}), Conns = ?DICT:store({LFrom, LTo}, wait_for_verification, StateData#state.connections), - change_shaper(StateData, jlib:make_jid("", LFrom, "")), + change_shaper(StateData, LTo, jlib:make_jid("", LFrom, "")), {next_state, stream_established, StateData#state{connections = Conns, @@ -326,8 +326,8 @@ send_element(Socket, El) -> send_text(Socket, xml:element_to_string(El)). -change_shaper(StateData, JID) -> - Shaper = acl:match_rule(StateData#state.shaper, JID), +change_shaper(StateData, Host, JID) -> + Shaper = acl:match_rule(Host, StateData#state.shaper, JID), ejabberd_receiver:change_shaper(StateData#state.receiver, Shaper). diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index 37411b1fc..1d88c09cc 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -283,7 +283,7 @@ handle_info({send_element, El}, StateName, StateData) -> send_element(StateData, El), {next_state, StateName, StateData}; handle_info({route, From, To, Packet}, StateName, StateData) -> - case acl:match_rule(StateData#state.access, From) of + case acl:match_rule(global, StateData#state.access, From) of allow -> {xmlelement, Name, Attrs, Els} = Packet, Attrs2 = jlib:replace_from_to_attrs(jlib:jid_to_string(From), diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 39a4beead..79876dd35 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -21,9 +21,9 @@ dirty_get_sessions_list/0, dirty_get_my_sessions_list/0, get_vh_session_list/1, - register_iq_handler/3, register_iq_handler/4, - unregister_iq_handler/1 + register_iq_handler/5, + unregister_iq_handler/2 ]). -include("ejabberd.hrl"). @@ -49,10 +49,13 @@ init() -> mnesia:add_table_index(presence, us), mnesia:subscribe(system), ets:new(sm_iqtable, [named_table]), - ejabberd_hooks:add(offline_message_hook, - ejabberd_sm, bounce_offline_message, 100), - ejabberd_hooks:add(remove_user, - ejabberd_sm, disconnect_removed_user, 100), + lists:foreach( + fun(Host) -> + ejabberd_hooks:add(offline_message_hook, Host, + ejabberd_sm, bounce_offline_message, 100), + ejabberd_hooks:add(remove_user, Host, + ejabberd_sm, disconnect_removed_user, 100) + end, ?MYHOSTS), loop(). loop() -> @@ -69,20 +72,20 @@ loop() -> {mnesia_system_event, {mnesia_down, Node}} -> clean_table_from_bad_node(Node), loop(); - {register_iq_handler, XMLNS, Module, Function} -> - ets:insert(sm_iqtable, {XMLNS, Module, Function}), + {register_iq_handler, Host, XMLNS, Module, Function} -> + ets:insert(sm_iqtable, {{XMLNS, Host}, Module, Function}), loop(); - {register_iq_handler, XMLNS, Module, Function, Opts} -> - ets:insert(sm_iqtable, {XMLNS, Module, Function, Opts}), + {register_iq_handler, Host, XMLNS, Module, Function, Opts} -> + ets:insert(sm_iqtable, {{XMLNS, Host}, Module, Function, Opts}), loop(); - {unregister_iq_handler, XMLNS} -> - case ets:lookup(sm_iqtable, XMLNS) of + {unregister_iq_handler, Host, XMLNS} -> + case ets:lookup(sm_iqtable, {XMLNS, Host}) of [{_, Module, Function, Opts}] -> gen_iq_handler:stop_iq_handler(Module, Function, Opts); _ -> ok end, - ets:delete(sm_iqtable, XMLNS), + ets:delete(sm_iqtable, {XMLNS, Host}), loop(); _ -> loop() @@ -170,24 +173,28 @@ do_route(From, To, Packet) -> "subscribe" -> {ejabberd_hooks:run_fold( roster_in_subscription, + LServer, false, [User, Server, From, subscribe]), true}; "subscribed" -> {ejabberd_hooks:run_fold( roster_in_subscription, + LServer, false, [User, Server, From, subscribed]), true}; "unsubscribe" -> {ejabberd_hooks:run_fold( roster_in_subscription, + LServer, false, [User, Server, From, unsubscribe]), true}; "unsubscribed" -> {ejabberd_hooks:run_fold( roster_in_subscription, + LServer, false, [User, Server, From, unsubscribed]), true}; @@ -220,6 +227,7 @@ do_route(From, To, Packet) -> true -> ejabberd_hooks:run( offline_subscription_hook, + LServer, [From, To, Packet]); _ -> Err = jlib:make_error_reply( @@ -298,6 +306,7 @@ route_message(From, To, Packet) -> case ejabberd_auth:is_user_exists(LUser, LServer) of true -> ejabberd_hooks:run(offline_message_hook, + LServer, [From, To, Packet]); _ -> Err = jlib:make_error_reply( @@ -354,7 +363,8 @@ unset_presence(User, Server, Resource, Status) -> mnesia:delete({presence, USR}) end, mnesia:transaction(F), - ejabberd_hooks:run(unset_presence_hook, [User, Server, Resource, Status]). + ejabberd_hooks:run(unset_presence_hook, jlib:nameprep(Server), + [User, Server, Resource, Status]). get_user_present_resources(LUser, LServer) -> US = {LUser, LServer}, @@ -392,7 +402,8 @@ process_iq(From, To, Packet) -> IQ = jlib:iq_query_info(Packet), case IQ of #iq{xmlns = XMLNS} -> - case ets:lookup(sm_iqtable, XMLNS) of + Host = To#jid.lserver, + case ets:lookup(sm_iqtable, {XMLNS, Host}) of [{_, Module, Function}] -> ResIQ = Module:Function(From, To, IQ), if @@ -403,7 +414,7 @@ process_iq(From, To, Packet) -> ok end; [{_, Module, Function, Opts}] -> - gen_iq_handler:handle(Module, Function, Opts, + gen_iq_handler:handle(Host, Module, Function, Opts, From, To, IQ); [] -> Err = jlib:make_error_reply( @@ -418,14 +429,14 @@ process_iq(From, To, Packet) -> ok end. -register_iq_handler(XMLNS, Module, Fun) -> - ejabberd_sm ! {register_iq_handler, XMLNS, Module, Fun}. +register_iq_handler(Host, XMLNS, Module, Fun) -> + ejabberd_sm ! {register_iq_handler, Host, XMLNS, Module, Fun}. -register_iq_handler(XMLNS, Module, Fun, Opts) -> - ejabberd_sm ! {register_iq_handler, XMLNS, Module, Fun, Opts}. +register_iq_handler(Host, XMLNS, Module, Fun, Opts) -> + ejabberd_sm ! {register_iq_handler, Host, XMLNS, Module, Fun, Opts}. -unregister_iq_handler(XMLNS) -> - ejabberd_sm ! {unregister_iq_handler, XMLNS}. +unregister_iq_handler(Host, XMLNS) -> + ejabberd_sm ! {unregister_iq_handler, Host, XMLNS}. diff --git a/src/gen_iq_handler.erl b/src/gen_iq_handler.erl index c9559628c..0a149994c 100644 --- a/src/gen_iq_handler.erl +++ b/src/gen_iq_handler.erl @@ -11,33 +11,33 @@ -vsn('$Revision$ '). -export([start/0, - start_link/2, - add_iq_handler/5, - remove_iq_handler/2, + start_link/3, + add_iq_handler/6, + remove_iq_handler/3, stop_iq_handler/3, - handle/6, - process_iq/5, - queue_init/2]). + handle/7, + process_iq/6, + queue_init/3]). -include("ejabberd.hrl"). start() -> ok. -add_iq_handler(Component, NS, Module, Function, Type) -> +add_iq_handler(Component, Host, NS, Module, Function, Type) -> case Type of no_queue -> - Component:register_iq_handler(NS, Module, Function, no_queue); + Component:register_iq_handler(Host, NS, Module, Function, no_queue); one_queue -> {ok, Pid} = supervisor:start_child(ejabberd_iq_sup, - [Module, Function]), - Component:register_iq_handler(NS, Module, Function, + [Host, Module, Function]), + Component:register_iq_handler(Host, NS, Module, Function, {one_queue, Pid}); parallel -> - Component:register_iq_handler(NS, Module, Function, parallel) + Component:register_iq_handler(Host, NS, Module, Function, parallel) end. -remove_iq_handler(Component, NS) -> +remove_iq_handler(Component, Host, NS) -> Component:unregister_iq_handler(NS). stop_iq_handler(Module, Function, Opts) -> @@ -48,20 +48,20 @@ stop_iq_handler(Module, Function, Opts) -> ok end. -handle(Module, Function, Opts, From, To, IQ) -> +handle(Host, Module, Function, Opts, From, To, IQ) -> case Opts of no_queue -> - process_iq(Module, Function, From, To, IQ); + process_iq(Host, Module, Function, From, To, IQ); {one_queue, Pid} -> Pid ! {process_iq, From, To, IQ}; parallel -> - spawn(?MODULE, process_iq, [Module, Function, From, To, IQ]); + spawn(?MODULE, process_iq, [Host, Module, Function, From, To, IQ]); _ -> todo end. -process_iq(Module, Function, From, To, IQ) -> +process_iq(_Host, Module, Function, From, To, IQ) -> case catch Module:Function(From, To, IQ) of {'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]); @@ -75,18 +75,18 @@ process_iq(Module, Function, From, To, IQ) -> end end. -start_link(Module, Function) -> - {ok, proc_lib:spawn_link(?MODULE, queue_init, [Module, Function])}. +start_link(Host, Module, Function) -> + {ok, proc_lib:spawn_link(?MODULE, queue_init, [Host, Module, Function])}. -queue_init(Module, Function) -> - queue_loop(Module, Function). +queue_init(Host, Module, Function) -> + queue_loop(Host, Module, Function). % TODO: use gen_event -queue_loop(Module, Function) -> +queue_loop(Host, Module, Function) -> receive {process_iq, From, To, IQ} -> - process_iq(Module, Function, From, To, IQ), - queue_loop(Module, Function); + process_iq(Host, Module, Function, From, To, IQ), + queue_loop(Host, Module, Function); _ -> - queue_loop(Module, Function) + queue_loop(Host, Module, Function) end. diff --git a/src/gen_mod.erl b/src/gen_mod.erl index 768869d52..70d1b0af6 100644 --- a/src/gen_mod.erl +++ b/src/gen_mod.erl @@ -11,58 +11,60 @@ -vsn('$Revision$ '). -export([start/0, - start_module/2, - stop_module/1, + start_module/3, + stop_module/2, get_opt/2, get_opt/3, - get_module_opt/3, - loaded_modules/0, - loaded_modules_with_opts/0, - get_hosts/2]). + get_module_opt/4, + loaded_modules/1, + loaded_modules_with_opts/1, + get_hosts/2, + get_module_proc/2]). -export([behaviour_info/1]). -include("ejabberd.hrl"). --record(ejabberd_module, {module, opts}). +-record(ejabberd_module, {module_host, opts}). behaviour_info(callbacks) -> - [{start, 1}, - {stop, 0}]; + [{start, 2}, + {stop, 1}]; behaviour_info(_Other) -> undefined. start() -> ets:new(ejabberd_modules, [named_table, public, - {keypos, #ejabberd_module.module}]), + {keypos, #ejabberd_module.module_host}]), ok. -start_module(Module, Opts) -> - case catch Module:start(Opts) of +start_module(Host, Module, Opts) -> + case catch Module:start(Host, Opts) of {'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]); _ -> - ets:insert(ejabberd_modules, #ejabberd_module{module = Module, - opts = Opts}), + ets:insert(ejabberd_modules, + #ejabberd_module{module_host = {Module, Host}, + opts = Opts}), ok end. -stop_module(Module) -> - case catch Module:stop() of +stop_module(Host, Module) -> + case catch Module:stop(Host) of {'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]); {wait, ProcList} when is_list(ProcList) -> lists:foreach(fun wait_for_process/1, ProcList), - ets:delete(ejabberd_modules, Module), + ets:delete(ejabberd_modules, {Module, Host}), ok; {wait, Process} -> wait_for_process(Process), - ets:delete(ejabberd_modules, Module), + ets:delete(ejabberd_modules, {Module, Host}), ok; _ -> - ets:delete(ejabberd_modules, Module), + ets:delete(ejabberd_modules, {Module, Host}), ok end. @@ -104,8 +106,8 @@ get_opt(Opt, Opts, Default) -> Val end. -get_module_opt(Module, Opt, Default) -> - OptsList = ets:lookup(ejabberd_modules, Module), +get_module_opt(Host, Module, Opt, Default) -> + OptsList = ets:lookup(ejabberd_modules, {Module, Host}), case OptsList of [] -> Default; @@ -113,15 +115,16 @@ get_module_opt(Module, Opt, Default) -> get_opt(Opt, Opts, Default) end. -loaded_modules() -> +loaded_modules(Host) -> ets:select(ejabberd_modules, - [{#ejabberd_module{_ = '_', module = '$1'}, + [{#ejabberd_module{_ = '_', module_host = {'$1', Host}}, [], ['$1']}]). -loaded_modules_with_opts() -> +loaded_modules_with_opts(Host) -> ets:select(ejabberd_modules, - [{#ejabberd_module{_ = '_', module = '$1', opts = '$2'}, + [{#ejabberd_module{_ = '_', module_host = {'$1', Host}, + opts = '$2'}, [], [{{'$1', '$2'}}]}]). @@ -137,3 +140,7 @@ get_hosts(Opts, Prefix) -> Hosts -> Hosts end. + +get_module_proc(Host, Base) -> + list_to_atom(atom_to_list(Base) ++ "_" ++ Host). + diff --git a/src/mod_announce.erl b/src/mod_announce.erl index b8581a376..2426ff371 100644 --- a/src/mod_announce.erl +++ b/src/mod_announce.erl @@ -11,9 +11,9 @@ -behaviour(gen_mod). --export([start/1, +-export([start/2, init/0, - stop/0, + stop/1, announce/3, send_motd/1]). @@ -25,17 +25,18 @@ -define(PROCNAME, ejabberd_announce). -start(_) -> +start(Host, _Opts) -> mnesia:create_table(motd, [{disc_copies, [node()]}, {attributes, record_info(fields, motd)}]), mnesia:create_table(motd_users, [{disc_copies, [node()]}, {attributes, record_info(fields, motd_users)}]), update_tables(), - ejabberd_hooks:add(local_send_to_resource_hook, + ejabberd_hooks:add(local_send_to_resource_hook, Host, ?MODULE, announce, 50), - ejabberd_hooks:add(user_available_hook, + ejabberd_hooks:add(user_available_hook, Host, ?MODULE, send_motd, 50), - register(?PROCNAME, proc_lib:spawn(?MODULE, init, [])). + register(gen_mod:get_module_proc(Host, ?PROCNAME), + proc_lib:spawn(?MODULE, init, [])). init() -> loop(). @@ -64,47 +65,50 @@ loop() -> loop() end. -stop() -> - ejabberd_hooks:delete(local_send_to_resource_hook, +stop(Host) -> + ejabberd_hooks:delete(local_send_to_resource_hook, Host, ?MODULE, announce, 50), - ejabberd_hooks:delete(sm_register_connection_hook, + ejabberd_hooks:delete(sm_register_connection_hook, Host, ?MODULE, send_motd, 50), - exit(whereis(?PROCNAME), stop), - {wait, ?PROCNAME}. + Proc = gen_mod:get_module_proc(Host, ?PROCNAME), + exit(whereis(Proc), stop), + {wait, Proc}. announce(From, To, Packet) -> case To of #jid{luser = "", lresource = Res} -> {xmlelement, Name, _Attrs, _Els} = Packet, - case {Res, Name} of - {"announce/all", "message"} -> - ?PROCNAME ! {announce_all, From, To, Packet}, - stop; - {"announce/online", "message"} -> - ?PROCNAME ! {announce_online, From, To, Packet}, - stop; - {"announce/all-hosts/online", "message"} -> - ?PROCNAME ! {announce_all_hosts_online, From, To, Packet}, - stop; - {"announce/motd", "message"} -> - ?PROCNAME ! {announce_motd, From, To, Packet}, - stop; - {"announce/motd/update", "message"} -> - ?PROCNAME ! {announce_motd_update, From, To, Packet}, - stop; - {"announce/motd/delete", "message"} -> - ?PROCNAME ! {announce_motd_delete, From, To, Packet}, - stop; - _ -> - ok + Proc = gen_mod:get_module_proc(To#jid.lserver, ?PROCNAME), + case {Res, Name} of + {"announce/all", "message"} -> + Proc ! {announce_all, From, To, Packet}, + stop; + {"announce/online", "message"} -> + Proc ! {announce_online, From, To, Packet}, + stop; + {"announce/all-hosts/online", "message"} -> + Proc ! {announce_all_hosts_online, From, To, Packet}, + stop; + {"announce/motd", "message"} -> + Proc ! {announce_motd, From, To, Packet}, + stop; + {"announce/motd/update", "message"} -> + Proc ! {announce_motd_update, From, To, Packet}, + stop; + {"announce/motd/delete", "message"} -> + Proc ! {announce_motd_delete, From, To, Packet}, + stop; + _ -> + ok end; _ -> ok end. announce_all(From, To, Packet) -> - Access = gen_mod:get_module_opt(?MODULE, access, none), - case acl:match_rule(Access, From) of + Host = To#jid.lserver, + Access = gen_mod:get_module_opt(Host, ?MODULE, access, none), + case acl:match_rule(Host, Access, From) of deny -> Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED), ejabberd_router:route(To, From, Err); @@ -114,24 +118,25 @@ announce_all(From, To, Packet) -> fun({User, Server}) -> Dest = jlib:make_jid(User, Server, ""), ejabberd_router:route(Local, Dest, Packet) - end, ejabberd_auth:get_vh_registered_users(To#jid.lserver)) + end, ejabberd_auth:get_vh_registered_users(Host)) end. announce_online(From, To, Packet) -> - Access = gen_mod:get_module_opt(?MODULE, access, none), - case acl:match_rule(Access, From) of + Host = To#jid.lserver, + Access = gen_mod:get_module_opt(Host, ?MODULE, access, none), + case acl:match_rule(Host, Access, From) of deny -> Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED), ejabberd_router:route(To, From, Err); allow -> - announce_online1(ejabberd_sm:get_vh_session_list(To#jid.lserver), + announce_online1(ejabberd_sm:get_vh_session_list(Host), To#jid.server, Packet) end. announce_all_hosts_online(From, To, Packet) -> - Access = gen_mod:get_module_opt(?MODULE, access, none), - case acl:match_rule(Access, From) of + Access = gen_mod:get_module_opt(global, ?MODULE, access, none), + case acl:match_rule(global, Access, From) of deny -> Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED), ejabberd_router:route(To, From, Err); @@ -150,14 +155,15 @@ announce_online1(Sessions, Server, Packet) -> end, Sessions). announce_motd(From, To, Packet) -> - Access = gen_mod:get_module_opt(?MODULE, access, none), - case acl:match_rule(Access, From) of + Host = To#jid.lserver, + Access = gen_mod:get_module_opt(Host, ?MODULE, access, none), + case acl:match_rule(Host, Access, From) of deny -> Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED), ejabberd_router:route(To, From, Err); allow -> announce_motd_update(To#jid.lserver, Packet), - Sessions = ejabberd_sm:get_vh_session_list(To#jid.lserver), + Sessions = ejabberd_sm:get_vh_session_list(Host), announce_online1(Sessions, To#jid.server, Packet), F = fun() -> lists:foreach( @@ -169,13 +175,14 @@ announce_motd(From, To, Packet) -> end. announce_motd_update(From, To, Packet) -> - Access = gen_mod:get_module_opt(?MODULE, access, none), - case acl:match_rule(Access, From) of + Host = To#jid.lserver, + Access = gen_mod:get_module_opt(Host, ?MODULE, access, none), + case acl:match_rule(Host, Access, From) of deny -> Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED), ejabberd_router:route(To, From, Err); allow -> - announce_motd_update(To#jid.lserver, Packet) + announce_motd_update(Host, Packet) end. announce_motd_update(LServer, Packet) -> @@ -186,13 +193,14 @@ announce_motd_update(LServer, Packet) -> mnesia:transaction(F). announce_motd_delete(From, To, Packet) -> - Access = gen_mod:get_module_opt(?MODULE, access, none), - case acl:match_rule(Access, From) of + Host = To#jid.lserver, + Access = gen_mod:get_module_opt(Host, ?MODULE, access, none), + case acl:match_rule(Host, Access, From) of deny -> Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED), ejabberd_router:route(To, From, Err); allow -> - announce_motd_delete(To#jid.lserver) + announce_motd_delete(Host) end. announce_motd_delete(LServer) -> diff --git a/src/mod_configure.erl b/src/mod_configure.erl index 6a896ffb1..435636884 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -12,8 +12,8 @@ -behaviour(gen_mod). --export([start/1, - stop/0, +-export([start/2, + stop/1, process_local_iq/3, process_sm_iq/3]). @@ -21,22 +21,22 @@ -include("jlib.hrl"). -start(Opts) -> +start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_EJABBERD_CONFIG, + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_EJABBERD_CONFIG, ?MODULE, process_local_iq, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_EJABBERD_CONFIG, + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_EJABBERD_CONFIG, ?MODULE, process_sm_iq, IQDisc), ok. -stop() -> - gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_EJABBERD_CONFIG), - gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_EJABBERD_CONFIG). +stop(Host) -> + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_EJABBERD_CONFIG), + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_EJABBERD_CONFIG). -process_local_iq(From, _To, #iq{id = ID, type = Type, xmlns = XMLNS, +process_local_iq(From, To, #iq{id = ID, type = Type, xmlns = XMLNS, lang = Lang, sub_el = SubEl} = IQ) -> - case acl:match_rule(configure, From) of + case acl:match_rule(To#jid.lserver, configure, From) of deny -> IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; allow -> @@ -719,7 +719,7 @@ search_running_node(SNode, [Node | Nodes]) -> process_sm_iq(From, To, #iq{type = Type, xmlns = XMLNS, lang = Lang, sub_el = SubEl} = IQ) -> - case acl:match_rule(configure, From) of + case acl:match_rule(To#jid.lserver, configure, From) of deny -> IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; allow -> diff --git a/src/mod_configure2.erl b/src/mod_configure2.erl index d22d344e4..0852546d4 100644 --- a/src/mod_configure2.erl +++ b/src/mod_configure2.erl @@ -12,8 +12,8 @@ -behaviour(gen_mod). --export([start/1, - stop/0, +-export([start/2, + stop/1, process_local_iq/3]). -include("ejabberd.hrl"). @@ -21,18 +21,18 @@ -define(NS_ECONFIGURE, "http://ejabberd.jabberstudio.org/protocol/configure"). -start(Opts) -> +start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_ECONFIGURE, + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_ECONFIGURE, ?MODULE, process_local_iq, IQDisc), ok. -stop() -> - gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_ECONFIGURE). +stop(Host) -> + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_ECONFIGURE). -process_local_iq(From, _To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> - case acl:match_rule(configure, From) of +process_local_iq(From, To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> + case acl:match_rule(To#jid.lserver, configure, From) of deny -> IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; allow -> diff --git a/src/mod_disco.erl b/src/mod_disco.erl index 769dc0416..16385441d 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -12,18 +12,18 @@ -behaviour(gen_mod). --export([start/1, - stop/0, +-export([start/2, + stop/1, process_local_iq_items/3, process_local_iq_info/3, process_sm_iq_items/3, process_sm_iq_info/3, - register_feature/1, - unregister_feature/1, + register_feature/2, + unregister_feature/2, register_extra_domain/1, unregister_extra_domain/1, - register_sm_feature/1, - unregister_sm_feature/1, + register_sm_feature/2, + unregister_sm_feature/2, register_sm_node/4, unregister_sm_node/1]). @@ -36,23 +36,23 @@ [{"xmlns", ?NS_DISCO_INFO}, {"node", SNode}], []}]}). -start(Opts) -> +start(Host, Opts) -> ejabberd_local:refresh_iq_handlers(), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_DISCO_ITEMS, + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_DISCO_ITEMS, ?MODULE, process_local_iq_items, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_DISCO_INFO, + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO, ?MODULE, process_local_iq_info, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_DISCO_ITEMS, + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_DISCO_ITEMS, ?MODULE, process_sm_iq_items, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_DISCO_INFO, + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_DISCO_INFO, ?MODULE, process_sm_iq_info, IQDisc), catch ets:new(disco_features, [named_table, ordered_set, public]), - register_feature("iq"), - register_feature("presence"), - register_feature("presence-invisible"), + register_feature(Host, "iq"), + register_feature(Host, "presence"), + register_feature(Host, "presence-invisible"), catch ets:new(disco_extra_domains, [named_table, ordered_set, public]), ExtraDomains = gen_mod:get_opt(extra_domains, Opts, []), @@ -61,23 +61,23 @@ start(Opts) -> catch ets:new(disco_sm_nodes, [named_table, ordered_set, public]), ok. -stop() -> - gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_DISCO_ITEMS), - gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_DISCO_INFO), - gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_DISCO_ITEMS), - gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_DISCO_INFO), +stop(Host) -> + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_ITEMS), + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO), + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_DISCO_ITEMS), + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_DISCO_INFO), catch ets:delete(disco_features), catch ets:delete(disco_extra_domains), ok. -register_feature(Feature) -> +register_feature(Host, Feature) -> catch ets:new(disco_features, [named_table, ordered_set, public]), - ets:insert(disco_features, {Feature}). + ets:insert(disco_features, {{Feature, Host}}). -unregister_feature(Feature) -> +unregister_feature(Host, Feature) -> catch ets:new(disco_features, [named_table, ordered_set, public]), - ets:delete(disco_features, Feature). + ets:delete(disco_features, {Feature, Host}). register_extra_domain(Domain) -> catch ets:new(disco_extra_domains, [named_table, ordered_set, public]), @@ -94,18 +94,19 @@ process_local_iq_items(From, To, #iq{type = Type, lang = Lang, sub_el = SubEl} = get -> SNode = xml:get_tag_attr_s("node", SubEl), Node = string:tokens(SNode, "/"), + Host = To#jid.lserver, - case acl:match_rule(configure, From) of + case acl:match_rule(Host, configure, From) of deny when Node /= [] -> IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; deny -> IQ#iq{type = result, sub_el = [{xmlelement, "query", [{"xmlns", ?NS_DISCO_ITEMS}], - get_services_only(To#jid.lserver) + get_services_only(Host) }]}; _ -> - case get_local_items(To#jid.lserver, Node, + case get_local_items(Host, Node, jlib:jid_to_string(To), Lang) of {result, Res} -> IQ#iq{type = result, @@ -121,7 +122,7 @@ process_local_iq_items(From, To, #iq{type = Type, lang = Lang, sub_el = SubEl} = end. -process_local_iq_info(From, _To, #iq{type = Type, xmlns = XMLNS, +process_local_iq_info(From, To, #iq{type = Type, xmlns = XMLNS, sub_el = SubEl} = IQ) -> case Type of set -> @@ -129,7 +130,7 @@ process_local_iq_info(From, _To, #iq{type = Type, xmlns = XMLNS, get -> SNode = xml:get_tag_attr_s("node", SubEl), Node = string:tokens(SNode, "/"), - case {acl:match_rule(configure, From), Node} of + case {acl:match_rule(To#jid.lserver, configure, From), Node} of {_, []} -> Features = lists:map(fun feature_to_xml/1, ets:tab2list(disco_features)), @@ -162,7 +163,7 @@ process_local_iq_info(From, _To, #iq{type = Type, xmlns = XMLNS, [{"category", "ejabberd"}, {"type", "node"}, {"name", ENode}], []}, - feature_to_xml({?NS_STATS}) + feature_to_xml(?NS_STATS) ] }]}; {allow, ["running nodes", ENode, "DB"]} -> @@ -171,7 +172,7 @@ process_local_iq_info(From, _To, #iq{type = Type, xmlns = XMLNS, "query", [{"xmlns", XMLNS}, {"node", SNode}], - [feature_to_xml({?NS_EJABBERD_CONFIG})]}]}; + [feature_to_xml(?NS_EJABBERD_CONFIG)]}]}; {allow, ["running nodes", ENode, "modules"]} -> ?EMPTY_INFO_RESULT; {allow, ["running nodes", ENode, "modules", _]} -> @@ -179,7 +180,7 @@ process_local_iq_info(From, _To, #iq{type = Type, xmlns = XMLNS, sub_el = [{xmlelement, "query", [{"xmlns", XMLNS}, {"node", SNode}], - [feature_to_xml({?NS_EJABBERD_CONFIG})]}]}; + [feature_to_xml(?NS_EJABBERD_CONFIG)]}]}; {allow, ["running nodes", ENode, "backup"]} -> ?EMPTY_INFO_RESULT; {allow, ["running nodes", ENode, "backup", _]} -> @@ -187,7 +188,7 @@ process_local_iq_info(From, _To, #iq{type = Type, xmlns = XMLNS, sub_el = [{xmlelement, "query", [{"xmlns", XMLNS}, {"node", SNode}], - [feature_to_xml({?NS_EJABBERD_CONFIG})]}]}; + [feature_to_xml(?NS_EJABBERD_CONFIG)]}]}; {allow, ["running nodes", ENode, "import"]} -> ?EMPTY_INFO_RESULT; {allow, ["running nodes", ENode, "import", _]} -> @@ -195,20 +196,22 @@ process_local_iq_info(From, _To, #iq{type = Type, xmlns = XMLNS, sub_el = [{xmlelement, "query", [{"xmlns", XMLNS}, {"node", SNode}], - [feature_to_xml({?NS_EJABBERD_CONFIG})]}]}; + [feature_to_xml(?NS_EJABBERD_CONFIG)]}]}; {allow, ["config", _]} -> IQ#iq{type = result, sub_el = [{xmlelement, "query", [{"xmlns", XMLNS}, {"node", SNode}], - [feature_to_xml({?NS_EJABBERD_CONFIG})]}]}; + [feature_to_xml(?NS_EJABBERD_CONFIG)]}]}; _ -> IQ#iq{type = error, sub_el = [SubEl, ?ERR_ITEM_NOT_FOUND]} end end. -feature_to_xml({Feature}) -> +feature_to_xml({{Feature, _Host}}) -> + feature_to_xml(Feature); +feature_to_xml(Feature) when is_list(Feature) -> {xmlelement, "feature", [{"var", Feature}], []}. domain_to_xml({Domain}) -> @@ -488,13 +491,13 @@ get_stopped_nodes(Lang) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -register_sm_feature(Feature) -> +register_sm_feature(Host, Feature) -> catch ets:new(disco_sm_features, [named_table, ordered_set, public]), - ets:insert(disco_sm_features, {Feature}). + ets:insert(disco_sm_features, {{Feature, Host}}). -unregister_sm_feature(Feature) -> +unregister_sm_feature(Host, Feature) -> catch ets:new(disco_sm_features, [named_table, ordered_set, public]), - ets:delete(disco_sm_features, Feature). + ets:delete(disco_sm_features, {Feature, Host}). register_sm_node(Node, Name, Module, Function) -> catch ets:new(disco_sm_nodes, [named_table, ordered_set, public]), @@ -509,7 +512,7 @@ process_sm_iq_items(From, To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ #jid{luser = LFrom, lserver = LServer} = From, Self = (LTo == LFrom) andalso (LServer == ?MYNAME), Node = xml:get_tag_attr_s("node", SubEl), - case {acl:match_rule(configure, From), Type, Self, Node} of + case {acl:match_rule(To#jid.lserver, configure, From), Type, Self, Node} of {_, set, _, _} -> IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; {_, get, true, []} -> @@ -561,7 +564,7 @@ process_sm_iq_info(From, To, #iq{type = Type, xmlns = XMLNS, #jid{luser = LFrom, lserver = LServer} = From, Self = (LTo == LFrom) andalso (LServer == ?MYNAME), Node = xml:get_tag_attr_s("node", SubEl), - case {acl:match_rule(configure, From), Type, Self, Node} of + case {acl:match_rule(To#jid.lserver, configure, From), Type, Self, Node} of {_, set, _, _} -> IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; {allow, get, _, []} -> @@ -569,7 +572,7 @@ process_sm_iq_info(From, To, #iq{type = Type, xmlns = XMLNS, ets:tab2list(disco_sm_features)), IQ#iq{type = result, sub_el = [{xmlelement, "query", [{"xmlns", XMLNS}], - [feature_to_xml({?NS_EJABBERD_CONFIG})] ++ + [feature_to_xml(?NS_EJABBERD_CONFIG)] ++ Features}]}; {_, get, _, []} -> Features = lists:map(fun feature_to_xml/1, diff --git a/src/mod_echo.erl b/src/mod_echo.erl index b93bba912..fd7e7ed37 100644 --- a/src/mod_echo.erl +++ b/src/mod_echo.erl @@ -12,17 +12,17 @@ -behaviour(gen_mod). --export([start/1, init/1, stop/0]). +-export([start/2, init/1, stop/1]). -include("ejabberd.hrl"). -include("jlib.hrl"). -define(PROCNAME, ejabberd_mod_echo). -start(Opts) -> - %Host = gen_mod:get_opt(host, Opts), - Host = gen_mod:get_opt(host, Opts, "echo." ++ ?MYNAME), - register(?PROCNAME, spawn(?MODULE, init, [Host])). +start(Host, Opts) -> + MyHost = gen_mod:get_opt(host, Opts, "echo." ++ Host), + register(gen_mod:get_module_proc(Host, ?PROCNAME), + spawn(?MODULE, init, [MyHost])). init(Host) -> ejabberd_router:register_route(Host), @@ -40,7 +40,8 @@ loop(Host) -> loop(Host) end. -stop() -> - ?PROCNAME ! stop, - {wait, ?PROCNAME}. +stop(Host) -> + Proc = gen_mod:get_module_proc(Host, ?PROCNAME), + Proc ! stop, + {wait, Proc}. diff --git a/src/mod_irc/mod_irc.erl b/src/mod_irc/mod_irc.erl index 9b05876fd..1192df510 100644 --- a/src/mod_irc/mod_irc.erl +++ b/src/mod_irc/mod_irc.erl @@ -12,7 +12,7 @@ -behaviour(gen_mod). --export([start/1, init/2, stop/0, +-export([start/2, init/2, stop/1, closed_connection/3, get_user_and_encoding/3]). @@ -26,44 +26,44 @@ -define(PROCNAME, ejabberd_mod_irc). -start(Opts) -> +start(Host, Opts) -> iconv:start(), mnesia:create_table(irc_custom, [{disc_copies, [node()]}, {attributes, record_info(fields, irc_custom)}]), - Hosts = gen_mod:get_hosts(Opts, "irc."), - Host = hd(Hosts), - update_table(Host), + MyHost = gen_mod:get_opt(host, Opts, "irc." ++ Host), + update_table(MyHost), Access = gen_mod:get_opt(access, Opts, all), - register(?PROCNAME, spawn(?MODULE, init, [Hosts, Access])). + register(gen_mod:get_module_proc(Host, ?PROCNAME), + spawn(?MODULE, init, [MyHost, Access])). -init(Hosts, Access) -> +init(Host, Access) -> catch ets:new(irc_connection, [named_table, public, {keypos, #irc_connection.jid_server_host}]), - ejabberd_router:register_routes(Hosts), - loop(Hosts, Access). + ejabberd_router:register_route(Host), + loop(Host, Access). -loop(Hosts, Access) -> +loop(Host, Access) -> receive {route, From, To, Packet} -> - case catch do_route(To#jid.lserver, Access, From, To, Packet) of + case catch do_route(Host, Access, From, To, Packet) of {'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]); _ -> ok end, - loop(Hosts, Access); + loop(Host, Access); stop -> - ejabberd_router:unregister_routes(Hosts), + ejabberd_router:unregister_route(Host), ok; _ -> - loop(Hosts, Access) + loop(Host, Access) end. do_route(Host, Access, From, To, Packet) -> - case acl:match_rule(Access, From) of + case acl:match_rule(Host, Access, From) of allow -> do_route1(Host, From, To, Packet); _ -> @@ -174,9 +174,10 @@ do_route1(Host, From, To, Packet) -> end. -stop() -> - ?PROCNAME ! stop, - {wait, ?PROCNAME}. +stop(Host) -> + Proc = gen_mod:get_module_proc(Host, ?PROCNAME), + Proc ! stop, + {wait, Proc}. closed_connection(Host, From, Server) -> diff --git a/src/mod_last.erl b/src/mod_last.erl index 33c9727a1..34ab81c6f 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -12,8 +12,8 @@ -behaviour(gen_mod). --export([start/1, - stop/0, +-export([start/2, + stop/1, process_local_iq/3, process_sm_iq/3, on_presence_update/4, @@ -26,28 +26,28 @@ -record(last_activity, {us, timestamp, status}). -start(Opts) -> +start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), mnesia:create_table(last_activity, [{disc_copies, [node()]}, {attributes, record_info(fields, last_activity)}]), update_table(), - gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_LAST, + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_LAST, ?MODULE, process_local_iq, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_LAST, + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_LAST, ?MODULE, process_sm_iq, IQDisc), - ejabberd_hooks:add(remove_user, + ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 50), - ejabberd_hooks:add(unset_presence_hook, + ejabberd_hooks:add(unset_presence_hook, Host, ?MODULE, on_presence_update, 50). -stop() -> - ejabberd_hooks:delete(remove_user, +stop(Host) -> + ejabberd_hooks:delete(remove_user, Host, ?MODULE, remove_user, 50), - ejabberd_hooks:delete(unset_presence_hook, + ejabberd_hooks:delete(unset_presence_hook, Host, ?MODULE, on_presence_update, 50), - gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_LAST), - gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_LAST). + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_LAST), + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_LAST). process_local_iq(_From, _To, #iq{type = Type, sub_el = SubEl} = IQ) -> case Type of @@ -72,7 +72,8 @@ process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) -> Server = To#jid.lserver, {Subscription, _Groups} = ejabberd_hooks:run_fold( - roster_get_jid_info, {none, []}, [User, Server, From]), + roster_get_jid_info, Server, + {none, []}, [User, Server, From]), if (Subscription == both) or (Subscription == from) -> case catch mod_privacy:get_user_list(User, Server) of diff --git a/src/mod_last_odbc.erl b/src/mod_last_odbc.erl index e7577ed40..ae63d9a8f 100644 --- a/src/mod_last_odbc.erl +++ b/src/mod_last_odbc.erl @@ -12,8 +12,8 @@ -behaviour(gen_mod). --export([start/1, - stop/0, +-export([start/2, + stop/1, process_local_iq/3, process_sm_iq/3, on_presence_update/4, @@ -24,24 +24,24 @@ -include("jlib.hrl"). -start(Opts) -> +start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_LAST, + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_LAST, ?MODULE, process_local_iq, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_LAST, + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_LAST, ?MODULE, process_sm_iq, IQDisc), - ejabberd_hooks:add(remove_user, + ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 50), - ejabberd_hooks:add(unset_presence_hook, + ejabberd_hooks:add(unset_presence_hook, Host, ?MODULE, on_presence_update, 50). -stop() -> - ejabberd_hooks:delete(remove_user, +stop(Host) -> + ejabberd_hooks:delete(remove_user, Host, ?MODULE, remove_user, 50), - ejabberd_hooks:delete(unset_presence_hook, + ejabberd_hooks:delete(unset_presence_hook, Host, ?MODULE, on_presence_update, 50), - gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_LAST), - gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_LAST). + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_LAST), + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_LAST). process_local_iq(_From, _To, #iq{type = Type, sub_el = SubEl} = IQ) -> case Type of @@ -66,7 +66,8 @@ process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) -> Server = To#jid.lserver, {Subscription, _Groups} = ejabberd_hooks:run_fold( - roster_get_jid_info, {none, []}, [User, From]), + roster_get_jid_info, Server, + {none, []}, [User, From]), if (Subscription == both) or (Subscription == from) -> case catch mod_privacy:get_user_list(User, Server) of diff --git a/src/mod_muc/mod_muc.erl b/src/mod_muc/mod_muc.erl index f3c61e595..5ebecf720 100644 --- a/src/mod_muc/mod_muc.erl +++ b/src/mod_muc/mod_muc.erl @@ -12,10 +12,10 @@ -behaviour(gen_mod). --export([start/1, - init/2, - stop/0, - room_destroyed/2, +-export([start/2, + init/3, + stop/1, + room_destroyed/3, store_room/3, restore_room/2, forget_room/2, @@ -32,60 +32,59 @@ -define(PROCNAME, ejabberd_mod_muc). -start(Opts) -> +start(Host, Opts) -> mnesia:create_table(muc_room, [{disc_copies, [node()]}, {attributes, record_info(fields, muc_room)}]), mnesia:create_table(muc_registered, [{disc_copies, [node()]}, {attributes, record_info(fields, muc_registered)}]), - Hosts = gen_mod:get_hosts(Opts, "conference."), - Host = hd(Hosts), - update_tables(Host), + MyHost = gen_mod:get_opt(host, Opts, "conference." ++ Host), + update_tables(MyHost), mnesia:add_table_index(muc_registered, nick), Access = gen_mod:get_opt(access, Opts, all), AccessCreate = gen_mod:get_opt(access_create, Opts, all), AccessAdmin = gen_mod:get_opt(access_admin, Opts, none), - register(?PROCNAME, + register(gen_mod:get_module_proc(Host, ?PROCNAME), spawn(?MODULE, init, - [Hosts, {Access, AccessCreate, AccessAdmin}])). + [MyHost, Host, {Access, AccessCreate, AccessAdmin}])). -init(Hosts, Access) -> +init(Host, ServerHost, Access) -> catch ets:new(muc_online_room, [named_table, public, {keypos, #muc_online_room.name_host}]), - ejabberd_router:register_routes(Hosts), - load_permanent_rooms(Access), - loop(Hosts, Access). + ejabberd_router:register_route(Host), + load_permanent_rooms(Host, ServerHost, Access), + loop(Host, ServerHost, Access). -loop(Hosts, Access) -> +loop(Host, ServerHost, Access) -> receive {route, From, To, Packet} -> - case catch do_route(To#jid.lserver, Access, From, To, Packet) of + case catch do_route(Host, ServerHost, Access, From, To, Packet) of {'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]); _ -> ok end, - loop(Hosts, Access); + loop(Host, ServerHost, Access); {room_destroyed, RoomHost} -> ets:delete(muc_online_room, RoomHost), - loop(Hosts, Access); + loop(Host, ServerHost, Access); stop -> - ejabberd_router:unregister_routes(Hosts), + ejabberd_router:unregister_route(Host), ok; _ -> - loop(Hosts, Access) + loop(Host, ServerHost, Access) end. -do_route(Host, Access, From, To, Packet) -> +do_route(Host, ServerHost, Access, From, To, Packet) -> {AccessRoute, _AccessCreate, _AccessAdmin} = Access, - case acl:match_rule(AccessRoute, From) of + case acl:match_rule(ServerHost, AccessRoute, From) of allow -> - do_route1(Host, Access, From, To, Packet); + do_route1(Host, ServerHost, Access, From, To, Packet); _ -> {xmlelement, _Name, Attrs, _Els} = Packet, Lang = xml:get_attr_s("xml:lang", Attrs), @@ -96,7 +95,7 @@ do_route(Host, Access, From, To, Packet) -> end. -do_route1(Host, Access, From, To, Packet) -> +do_route1(Host, ServerHost, Access, From, To, Packet) -> {_AccessRoute, AccessCreate, AccessAdmin} = Access, {Room, _, Nick} = jlib:jid_tolower(To), {xmlelement, Name, Attrs, _Els} = Packet, @@ -178,7 +177,7 @@ do_route1(Host, Access, From, To, Packet) -> "error" -> ok; _ -> - case acl:match_rule(AccessAdmin, From) of + case acl:match_rule(ServerHost, AccessAdmin, From) of allow -> Msg = xml:get_path_s( Packet, @@ -216,11 +215,12 @@ do_route1(Host, Access, From, To, Packet) -> Type = xml:get_attr_s("type", Attrs), case {Name, Type} of {"presence", ""} -> - case acl:match_rule(AccessCreate, From) of + case acl:match_rule(ServerHost, AccessCreate, From) of allow -> ?DEBUG("MUC: open new room '~s'~n", [Room]), {ok, Pid} = mod_muc_room:start( - Host, Access, Room, From, Nick), + Host, ServerHost, Access, + Room, From, Nick), ets:insert( muc_online_room, #muc_online_room{name_host = {Room, Host}, @@ -252,13 +252,15 @@ do_route1(Host, Access, From, To, Packet) -> -room_destroyed(Host, Room) -> - ?PROCNAME ! {room_destroyed, {Room, Host}}, +room_destroyed(Host, Room, ServerHost) -> + gen_mod:get_module_proc(ServerHost, ?PROCNAME) ! + {room_destroyed, {Room, Host}}, ok. -stop() -> - ?PROCNAME ! stop, - {wait, ?PROCNAME}. +stop(Host) -> + Proc = gen_mod:get_module_proc(Host, ?PROCNAME), + Proc ! stop, + {wait, Proc}. store_room(Host, Name, Opts) -> @@ -284,8 +286,11 @@ forget_room(Host, Name) -> mnesia:transaction(F). -load_permanent_rooms(Access) -> - case catch mnesia:dirty_select(muc_room, [{'_', [], ['$_']}]) of +load_permanent_rooms(Host, ServerHost, Access) -> + case catch mnesia:dirty_select( + muc_room, [{#muc_room{name_host = {'_', Host}, _ = '_'}, + [], + ['$_']}]) of {'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]), ok; @@ -294,6 +299,7 @@ load_permanent_rooms(Access) -> {Room, Host} = R#muc_room.name_host, {ok, Pid} = mod_muc_room:start( Host, + ServerHost, Access, Room, R#muc_room.opts), diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index b1a5d4017..15bacbfe2 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -14,8 +14,8 @@ %% External exports --export([start/5, - start/4, +-export([start/6, + start/5, route/4]). %% gen_fsm callbacks @@ -59,6 +59,7 @@ -record(state, {room, host, + server_host, access, jid, config = #config{}, @@ -82,11 +83,12 @@ %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- -start(Host, Access, Room, Creator, Nick) -> - gen_fsm:start(?MODULE, [Host, Access, Room, Creator, Nick], ?FSMOPTS). +start(Host, ServerHost, Access, Room, Creator, Nick) -> + gen_fsm:start(?MODULE, [Host, ServerHost, Access, Room, Creator, Nick], + ?FSMOPTS). -start(Host, Access, Room, Opts) -> - gen_fsm:start(?MODULE, [Host, Access, Room, Opts], ?FSMOPTS). +start(Host, ServerHost, Access, Room, Opts) -> + gen_fsm:start(?MODULE, [Host, ServerHost, Access, Room, Opts], ?FSMOPTS). %%%---------------------------------------------------------------------- %%% Callback functions from gen_fsm @@ -99,16 +101,18 @@ start(Host, Access, Room, Opts) -> %% ignore | %% {stop, StopReason} %%---------------------------------------------------------------------- -init([Host, Access, Room, Creator, Nick]) -> +init([Host, ServerHost, Access, Room, Creator, Nick]) -> State = set_affiliation(Creator, owner, #state{host = Host, + server_host = ServerHost, access = Access, room = Room, jid = jlib:make_jid(Room, Host, ""), just_created = true}), {ok, normal_state, State}; -init([Host, Access, Room, Opts]) -> +init([Host, ServerHost, Access, Room, Opts]) -> State = set_opts(Opts, #state{host = Host, + server_host = ServerHost, access = Access, room = Room, jid = jlib:make_jid(Room, Host, "")}), @@ -652,7 +656,8 @@ handle_info(_Info, StateName, StateData) -> %% Returns: any %%---------------------------------------------------------------------- terminate(_Reason, _StateName, StateData) -> - mod_muc:room_destroyed(StateData#state.host, StateData#state.room), + mod_muc:room_destroyed(StateData#state.host, StateData#state.room, + StateData#state.server_host), ok. %%%---------------------------------------------------------------------- @@ -732,7 +737,7 @@ set_affiliation_and_reason(JID, Affiliation, Reason, StateData) -> get_affiliation(JID, StateData) -> {_AccessRoute, _AccessCreate, AccessAdmin} = StateData#state.access, Res = - case acl:match_rule(AccessAdmin, JID) of + case acl:match_rule(StateData#state.server_host, AccessAdmin, JID) of allow -> owner; _ -> diff --git a/src/mod_offline.erl b/src/mod_offline.erl index 1c79d6a5d..a289c9195 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -11,9 +11,9 @@ -behaviour(gen_mod). --export([start/1, +-export([start/2, init/0, - stop/0, + stop/1, store_packet/3, resend_offline_messages/2, pop_offline_messages/3, @@ -29,21 +29,22 @@ -define(PROCNAME, ejabberd_offline). -define(OFFLINE_TABLE_LOCK_THRESHOLD, 1000). -start(_) -> +start(Host, _Opts) -> mnesia:create_table(offline_msg, [{disc_only_copies, [node()]}, {type, bag}, {attributes, record_info(fields, offline_msg)}]), update_table(), - ejabberd_hooks:add(offline_message_hook, + ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, store_packet, 50), - ejabberd_hooks:add(offline_subscription_hook, + ejabberd_hooks:add(offline_subscription_hook, Host, ?MODULE, store_packet, 50), - ejabberd_hooks:add(resend_offline_messages_hook, + ejabberd_hooks:add(resend_offline_messages_hook, Host, ?MODULE, pop_offline_messages, 50), - ejabberd_hooks:add(remove_user, + ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 50), - register(?PROCNAME, spawn(?MODULE, init, [])). + register(gen_mod:get_module_proc(Host, ?PROCNAME), + spawn(?MODULE, init, [])). init() -> loop(). @@ -79,17 +80,18 @@ receive_all(Msgs) -> end. -stop() -> - ejabberd_hooks:delete(offline_message_hook, +stop(Host) -> + ejabberd_hooks:delete(offline_message_hook, Host, ?MODULE, store_packet, 50), - ejabberd_hooks:delete(offline_subscription_hook, + ejabberd_hooks:delete(offline_subscription_hook, Host, ?MODULE, store_packet, 50), - ejabberd_hooks:delete(resend_offline_messages_hook, + ejabberd_hooks:delete(resend_offline_messages_hook, Host, ?MODULE, pop_offline_messages, 50), - ejabberd_hooks:delete(remove_user, + ejabberd_hooks:delete(remove_user, Host, ?MODULE, remove_user, 50), - exit(whereis(?PROCNAME), stop), - {wait, ?PROCNAME}. + Proc = gen_mod:get_module_proc(Host, ?PROCNAME), + exit(whereis(Proc), stop), + {wait, Proc}. store_packet(From, To, Packet) -> Type = xml:get_tag_attr_s("type", Packet), diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index e2f87c67c..253db1cc4 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -11,9 +11,9 @@ -behaviour(gen_mod). --export([start/1, +-export([start/2, init/0, - stop/0, + stop/1, store_packet/3, pop_offline_messages/2, remove_user/1]). @@ -26,16 +26,16 @@ -define(PROCNAME, ejabberd_offline). -define(OFFLINE_TABLE_LOCK_THRESHOLD, 1000). -start(_) -> +start(Host, _Opts) -> % TODO: remove ejabberd_odbc:start(), - ejabberd_hooks:add(offline_message_hook, + ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, store_packet, 50), - ejabberd_hooks:add(offline_subscription_hook, + ejabberd_hooks:add(offline_subscription_hook, Host, ?MODULE, store_packet, 50), - ejabberd_hooks:add(resend_offline_messages_hook, + ejabberd_hooks:add(resend_offline_messages_hook, Host, ?MODULE, pop_offline_messages, 50), - ejabberd_hooks:add(remove_user, + ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 50), register(?PROCNAME, spawn(?MODULE, init, [])). @@ -95,14 +95,14 @@ receive_all(Msgs) -> end. -stop() -> - ejabberd_hooks:delete(offline_message_hook, +stop(Host) -> + ejabberd_hooks:delete(offline_message_hook, Host, ?MODULE, store_packet, 50), - ejabberd_hooks:delete(offline_subscription_hook, + ejabberd_hooks:delete(offline_subscription_hook, Host, ?MODULE, store_packet, 50), - ejabberd_hooks:delete(resend_offline_messages_hook, + ejabberd_hooks:delete(resend_offline_messages_hook, Host, ?MODULE, pop_offline_messages, 50), - ejabberd_hooks:delete(remove_user, + ejabberd_hooks:delete(remove_user, Host, ?MODULE, remove_user, 50), exit(whereis(?PROCNAME), stop), ok. diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index f13f145f5..e1e2bf1b2 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -12,7 +12,7 @@ -behaviour(gen_mod). --export([start/1, stop/0, +-export([start/2, stop/1, process_iq/3, process_iq_set/3, process_iq_get/4, @@ -42,16 +42,16 @@ -record(userlist, {name = none, list = []}). -start(Opts) -> +start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), mnesia:create_table(privacy, [{disc_copies, [node()]}, {attributes, record_info(fields, privacy)}]), update_table(), - gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_PRIVACY, + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_PRIVACY, ?MODULE, process_iq, IQDisc). -stop() -> - gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_PRIVACY). +stop(Host) -> + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_PRIVACY). process_iq(From, _To, IQ) -> #iq{type = Type, sub_el = SubEl} = IQ, @@ -555,32 +555,32 @@ check_packet(User, Server, LJID = jlib:jid_tolower(From), {Subscription, Groups} = ejabberd_hooks:run_fold( - roster_get_jid_info, {none, []}, - [User, Server, LJID]), + roster_get_jid_info, jlib:nameprep(Server), + {none, []}, [User, Server, LJID]), check_packet_aux(List, message, LJID, Subscription, Groups); {iq, in} -> LJID = jlib:jid_tolower(From), {Subscription, Groups} = ejabberd_hooks:run_fold( - roster_get_jid_info, {none, []}, - [User, Server, LJID]), + roster_get_jid_info, jlib:nameprep(Server), + {none, []}, [User, Server, LJID]), check_packet_aux(List, iq, LJID, Subscription, Groups); {presence, in} -> LJID = jlib:jid_tolower(From), {Subscription, Groups} = ejabberd_hooks:run_fold( - roster_get_jid_info, {none, []}, - [User, Server, LJID]), + roster_get_jid_info, jlib:nameprep(Server), + {none, []}, [User, Server, LJID]), check_packet_aux(List, presence_in, LJID, Subscription, Groups); {presence, out} -> LJID = jlib:jid_tolower(To), {Subscription, Groups} = ejabberd_hooks:run_fold( - roster_get_jid_info, {none, []}, - [User, Server, LJID]), + roster_get_jid_info, jlib:nameprep(Server), + {none, []}, [User, Server, LJID]), check_packet_aux(List, presence_out, LJID, Subscription, Groups); _ -> @@ -592,12 +592,12 @@ check_packet_aux([], _PType, _JID, _Subscription, _Groups) -> allow; check_packet_aux([Item | List], PType, JID, Subscription, Groups) -> #listitem{type = Type, value = Value, action = Action} = Item, - case Type of - none -> - Action; - _ -> - case is_ptype_match(Item, PType) of - true -> + case is_ptype_match(Item, PType) of + true -> + case Type of + none -> + Action; + _ -> case is_type_match(Type, Value, JID, Subscription, Groups) of true -> @@ -605,10 +605,10 @@ check_packet_aux([Item | List], PType, JID, Subscription, Groups) -> false -> check_packet_aux(List, PType, JID, Subscription, Groups) - end; - false -> - check_packet_aux(List, PType, JID, Subscription, Groups) - end + end + end; + false -> + check_packet_aux(List, PType, JID, Subscription, Groups) end. diff --git a/src/mod_private.erl b/src/mod_private.erl index 109817244..6b8925dda 100644 --- a/src/mod_private.erl +++ b/src/mod_private.erl @@ -12,8 +12,8 @@ -behaviour(gen_mod). --export([start/1, - stop/0, +-export([start/2, + stop/1, process_sm_iq/3, remove_user/2]). @@ -22,21 +22,21 @@ -record(private_storage, {usns, xml}). -start(Opts) -> +start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), mnesia:create_table(private_storage, [{disc_only_copies, [node()]}, {attributes, record_info(fields, private_storage)}]), update_table(), - ejabberd_hooks:add(remove_user, + ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 50), - gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_PRIVATE, + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_PRIVATE, ?MODULE, process_sm_iq, IQDisc). -stop() -> - ejabberd_hooks:delete(remove_user, +stop(Host) -> + ejabberd_hooks:delete(remove_user, Host, ?MODULE, remove_user, 50), - gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_PRIVATE). + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_PRIVATE). process_sm_iq(From, _To, #iq{type = Type, sub_el = SubEl} = IQ) -> diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 40cdabc44..ee4ce1c28 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -12,10 +12,10 @@ -behaviour(gen_mod). --export([start/1, - init/3, +-export([start/2, + init/4, loop/2, - stop/0, + stop/1, system_continue/3, system_terminate/4, system_code_change/4]). @@ -37,37 +37,34 @@ -define(PROCNAME, ejabberd_mod_pubsub). -start(Opts) -> +start(Host, Opts) -> mnesia:create_table(pubsub_node, [{disc_only_copies, [node()]}, {attributes, record_info(fields, pubsub_node)}]), - Hosts = gen_mod:get_hosts(Opts, "pubsub."), - Host = hd(Hosts), - update_table(Host), + MyHost = gen_mod:get_opt(host, Opts, "pubsub." ++ Host), + update_table(MyHost), mnesia:add_table_index(pubsub_node, host_parent), ServedHosts = gen_mod:get_opt(served_hosts, Opts, []), - register(?PROCNAME, - proc_lib:spawn_link(?MODULE, init, [Hosts, ServedHosts, self()])). + register(gen_mod:get_module_proc(Host, ?PROCNAME), + proc_lib:spawn_link(?MODULE, init, + [MyHost, Host, ServedHosts, self()])). -define(MYJID, #jid{user = "", server = Host, resource = "", luser = "", lserver = Host, lresource = ""}). -init(Hosts, ServedHosts, Parent) -> - ejabberd_router:register_routes(Hosts), - lists:foreach( - fun(Host) -> - create_new_node(Host, ["pubsub"], ?MYJID), - create_new_node(Host, ["pubsub", "nodes"], ?MYJID), - create_new_node(Host, ["home"], ?MYJID), - create_new_node(Host, ["home", find_my_host(Host)], ?MYJID), - lists:foreach(fun(H) -> - create_new_node(Host, ["home", H], ?MYJID) - end, ServedHosts) - end, Hosts), - loop(Hosts, Parent). - -loop(Hosts, Parent) -> +init(Host, ServerHost, ServedHosts, Parent) -> + ejabberd_router:register_route(Host), + create_new_node(Host, ["pubsub"], ?MYJID), + create_new_node(Host, ["pubsub", "nodes"], ?MYJID), + create_new_node(Host, ["home"], ?MYJID), + create_new_node(Host, ["home", ServerHost], ?MYJID), + lists:foreach(fun(H) -> + create_new_node(Host, ["home", H], ?MYJID) + end, ServedHosts), + loop(Host, Parent). + +loop(Host, Parent) -> receive {route, From, To, Packet} -> case catch do_route(To#jid.lserver, From, To, Packet) of @@ -76,19 +73,19 @@ loop(Hosts, Parent) -> _ -> ok end, - loop(Hosts, Parent); + loop(Host, Parent); {room_destroyed, Room} -> ets:delete(muc_online_room, Room), - loop(Hosts, Parent); + loop(Host, Parent); stop -> - ejabberd_router:unregister_routes(Hosts), + ejabberd_router:unregister_route(Host), ok; reload -> - ?MODULE:loop(Hosts, Parent); + ?MODULE:loop(Host, Parent); {system, From, Request} -> - sys:handle_system_msg(Request, From, Parent, ?MODULE, [], Hosts); + sys:handle_system_msg(Request, From, Parent, ?MODULE, [], Host); _ -> - loop(Hosts, Parent) + loop(Host, Parent) end. @@ -202,9 +199,10 @@ do_route(Host, From, To, Packet) -> -stop() -> - ?PROCNAME ! stop, - {wait, ?PROCNAME}. +stop(Host) -> + Proc = gen_mod:get_module_proc(Host, ?PROCNAME), + Proc ! stop, + {wait, Proc}. @@ -1177,26 +1175,6 @@ system_code_change(State, _Mod, Ver, _Extra) -> -find_my_host(LServer) -> - Parts = string:tokens(LServer, "."), - find_my_host(Parts, ?MYHOSTS). - -find_my_host([], _Hosts) -> - ?MYNAME; -find_my_host([_ | Tail] = Parts, Hosts) -> - Domain = parts_to_string(Parts), - case lists:member(Domain, Hosts) of - true -> - Domain; - false -> - find_my_host(Tail, Hosts) - end. - -parts_to_string(Parts) -> - string:strip(lists:flatten(lists:map(fun(S) -> [S, $.] end, Parts)), - right, $.). - - update_table(Host) -> Fields = record_info(fields, pubsub_node), diff --git a/src/mod_register.erl b/src/mod_register.erl index 68ead661a..0db873930 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -1,7 +1,7 @@ %%%---------------------------------------------------------------------- %%% File : mod_register.erl %%% Author : Alexey Shchepin <alexey@sevcom.net> -%%% Purpose : +%%% Purpose : Inband registration support %%% Created : 8 Dec 2002 by Alexey Shchepin <alexey@sevcom.net> %%% Id : $Id$ %%%---------------------------------------------------------------------- @@ -12,24 +12,27 @@ -behaviour(gen_mod). --export([start/1, stop/0, process_iq/3]). +-export([start/2, + stop/1, + process_iq/3]). -include("ejabberd.hrl"). -include("jlib.hrl"). -start(Opts) -> +start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_REGISTER, + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_REGISTER, ?MODULE, process_iq, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_REGISTER, + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_REGISTER, ?MODULE, process_iq, IQDisc), ok. -stop() -> - gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_REGISTER), - gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_REGISTER). +stop(Host) -> + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_REGISTER), + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_REGISTER). -process_iq(From, To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> +process_iq(From, To, + #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> case Type of set -> UTag = xml:get_subtag(SubEl, "username"), @@ -123,8 +126,8 @@ try_register(User, Server, Password) -> {error, ?ERR_BAD_REQUEST}; _ -> JID = jlib:make_jid(User, Server, ""), - Access = gen_mod:get_module_opt(?MODULE, access, all), - case acl:match_rule(Access, JID) of + Access = gen_mod:get_module_opt(Server, ?MODULE, access, all), + case acl:match_rule(Server, Access, JID) of deny -> {error, ?ERR_CONFLICT}; allow -> diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 88db5d192..48e2c1e8b 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -12,7 +12,7 @@ -behaviour(gen_mod). --export([start/1, stop/0, +-export([start/2, stop/1, process_iq/3, process_local_iq/3, get_user_roster/2, @@ -28,41 +28,41 @@ -include("mod_roster.hrl"). -start(Opts) -> +start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), mnesia:create_table(roster,[{disc_copies, [node()]}, {attributes, record_info(fields, roster)}]), update_table(), mnesia:add_table_index(roster, us), - ejabberd_hooks:add(roster_get, + ejabberd_hooks:add(roster_get, Host, ?MODULE, get_user_roster, 50), - ejabberd_hooks:add(roster_in_subscription, + ejabberd_hooks:add(roster_in_subscription, Host, ?MODULE, in_subscription, 50), - ejabberd_hooks:add(roster_out_subscription, + ejabberd_hooks:add(roster_out_subscription, Host, ?MODULE, out_subscription, 50), - ejabberd_hooks:add(roster_get_subscription_lists, + ejabberd_hooks:add(roster_get_subscription_lists, Host, ?MODULE, get_subscription_lists, 50), - ejabberd_hooks:add(roster_get_jid_info, + ejabberd_hooks:add(roster_get_jid_info, Host, ?MODULE, get_jid_info, 50), - ejabberd_hooks:add(remove_user, + ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 50), - gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_ROSTER, + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_ROSTER, ?MODULE, process_iq, IQDisc). -stop() -> - ejabberd_hooks:delete(roster_get, +stop(Host) -> + ejabberd_hooks:delete(roster_get, Host, ?MODULE, get_user_roster, 50), - ejabberd_hooks:delete(roster_in_subscription, + ejabberd_hooks:delete(roster_in_subscription, Host, ?MODULE, in_subscription, 50), - ejabberd_hooks:delete(roster_out_subscription, + ejabberd_hooks:delete(roster_out_subscription, Host, ?MODULE, out_subscription, 50), - ejabberd_hooks:delete(roster_get_subscription_lists, + ejabberd_hooks:delete(roster_get_subscription_lists, Host, ?MODULE, get_subscription_lists, 50), - ejabberd_hooks:delete(roster_get_jid_info, + ejabberd_hooks:delete(roster_get_jid_info, Host, ?MODULE, get_jid_info, 50), - ejabberd_hooks:delete(remove_user, + ejabberd_hooks:delete(remove_user, Host, ?MODULE, remove_user, 50), - gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_ROSTER). + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_ROSTER). -define(PSI_ROSTER_WORKAROUND, true). @@ -106,11 +106,11 @@ process_local_iq(From, To, #iq{type = Type} = IQ) -> -process_iq_get(From, _To, #iq{sub_el = SubEl} = IQ) -> +process_iq_get(From, To, #iq{sub_el = SubEl} = IQ) -> LUser = From#jid.luser, LServer = From#jid.lserver, US = {LUser, LServer}, - case catch ejabberd_hooks:run_fold(roster_get, [], [US]) of + case catch ejabberd_hooks:run_fold(roster_get, To#jid.lserver, [], [US]) of Items when is_list(Items) -> XItems = lists:map(fun item_to_xml/1, Items), IQ#iq{type = result, diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index 390689a43..1f0c01642 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -12,7 +12,7 @@ -behaviour(gen_mod). --export([start/1, stop/0, +-export([start/2, stop/1, process_iq/3, process_local_iq/3, get_subscription_lists/2, @@ -31,35 +31,35 @@ subscription = none, ask = none}). -start(Opts) -> +start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - ejabberd_hooks:add(roster_out_subscription, + ejabberd_hooks:add(roster_out_subscription, Host, ?MODULE, out_subscription, 50), - ejabberd_hooks:add(roster_in_subscription, + ejabberd_hooks:add(roster_in_subscription, Host, ?MODULE, in_subscription, 50), - ejabberd_hooks:add(roster_out_subscription, + ejabberd_hooks:add(roster_out_subscription, Host, ?MODULE, out_subscription, 50), - ejabberd_hooks:add(roster_get_subscription_lists, + ejabberd_hooks:add(roster_get_subscription_lists, Host, ?MODULE, get_subscription_lists, 50), - ejabberd_hooks:add(roster_get_jid_info, + ejabberd_hooks:add(roster_get_jid_info, Host, ?MODULE, get_jid_info, 50), - ejabberd_hooks:add(remove_user, + ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 50), - gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_ROSTER, + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_ROSTER, ?MODULE, process_iq, IQDisc). -stop() -> - ejabberd_hooks:delete(roster_in_subscription, +stop(Host) -> + ejabberd_hooks:delete(roster_in_subscription, Host, ?MODULE, in_subscription, 50), - ejabberd_hooks:delete(roster_out_subscription, + ejabberd_hooks:delete(roster_out_subscription, Host, ?MODULE, out_subscription, 50), - ejabberd_hooks:delete(roster_get_subscription_lists, + ejabberd_hooks:delete(roster_get_subscription_lists, Host, ?MODULE, get_subscription_lists, 50), - ejabberd_hooks:delete(roster_get_jid_info, + ejabberd_hooks:delete(roster_get_jid_info, Host, ?MODULE, get_jid_info, 50), - ejabberd_hooks:delete(remove_user, + ejabberd_hooks:delete(remove_user, Host, ?MODULE, remove_user, 50), - gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_ROSTER). + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_ROSTER). -define(PSI_ROSTER_WORKAROUND, true). diff --git a/src/mod_service_log.erl b/src/mod_service_log.erl index 0203579b1..b3c7c53ba 100644 --- a/src/mod_service_log.erl +++ b/src/mod_service_log.erl @@ -11,25 +11,25 @@ -behaviour(gen_mod). --export([start/1, - stop/0, +-export([start/2, + stop/1, log_user_send/3, log_user_receive/4]). -include("ejabberd.hrl"). -include("jlib.hrl"). -start(_) -> - ejabberd_hooks:add(user_send_packet, +start(Host, _Opts) -> + ejabberd_hooks:add(user_send_packet, Host, ?MODULE, log_user_send, 50), - ejabberd_hooks:add(user_receive_packet, + ejabberd_hooks:add(user_receive_packet, Host, ?MODULE, log_user_receive, 50), ok. -stop() -> - ejabberd_hooks:delete(user_send_packet, +stop(Host) -> + ejabberd_hooks:delete(user_send_packet, Host, ?MODULE, log_user_send, 50), - ejabberd_hooks:delete(user_receive_packet, + ejabberd_hooks:delete(user_receive_packet, Host, ?MODULE, log_user_receive, 50), ok. @@ -41,9 +41,10 @@ log_user_receive(_JID, From, To, Packet) -> log_packet(From, To, {xmlelement, Name, Attrs, Els}) -> - Loggers = gen_mod:get_module_opt(?MODULE, loggers, []), - ServerJID = #jid{user = "", server = ?MYNAME, resource = "", - luser = "", lserver = ?MYNAME, lresource = ""}, + Host = From#jid.lserver, + Loggers = gen_mod:get_module_opt(Host, ?MODULE, loggers, []), + ServerJID = #jid{user = "", server = Host, resource = "", + luser = "", lserver = Host, lresource = ""}, NewAttrs = jlib:replace_from_to_attrs(jlib:jid_to_string(From), jlib:jid_to_string(To), Attrs), diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index 3566da245..f610305c8 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -12,7 +12,7 @@ -behaviour(gen_mod). --export([start/1, stop/0, +-export([start/2, stop/1, get_user_roster/2, get_subscription_lists/3, get_jid_info/4, @@ -35,7 +35,7 @@ -record(sr_group, {group_host, opts}). -record(sr_user, {us, group_host}). -start(_Opts) -> +start(Host, _Opts) -> mnesia:create_table(sr_group, [{disc_copies, [node()]}, {attributes, record_info(fields, sr_group)}]), @@ -44,31 +44,31 @@ start(_Opts) -> {type, bag}, {attributes, record_info(fields, sr_user)}]), mnesia:add_table_index(sr_user, group_host), - ejabberd_hooks:add(roster_get, + ejabberd_hooks:add(roster_get, Host, ?MODULE, get_user_roster, 70), - ejabberd_hooks:add(roster_in_subscription, + ejabberd_hooks:add(roster_in_subscription, Host, ?MODULE, in_subscription, 30), - ejabberd_hooks:add(roster_out_subscription, + ejabberd_hooks:add(roster_out_subscription, Host, ?MODULE, out_subscription, 30), - ejabberd_hooks:add(roster_get_subscription_lists, + ejabberd_hooks:add(roster_get_subscription_lists, Host, ?MODULE, get_subscription_lists, 70), - ejabberd_hooks:add(roster_get_jid_info, + ejabberd_hooks:add(roster_get_jid_info, Host, ?MODULE, get_jid_info, 70). - %ejabberd_hooks:add(remove_user, + %ejabberd_hooks:add(remove_user, Host, % ?MODULE, remove_user, 50), -stop() -> - ejabberd_hooks:delete(roster_get, +stop(Host) -> + ejabberd_hooks:delete(roster_get, Host, ?MODULE, get_user_roster, 70), - ejabberd_hooks:delete(roster_in_subscription, + ejabberd_hooks:delete(roster_in_subscription, Host, ?MODULE, in_subscription, 30), - ejabberd_hooks:delete(roster_out_subscription, + ejabberd_hooks:delete(roster_out_subscription, Host, ?MODULE, out_subscription, 30), - ejabberd_hooks:delete(roster_get_subscription_lists, + ejabberd_hooks:delete(roster_get_subscription_lists, Host, ?MODULE, get_subscription_lists, 70), - ejabberd_hooks:delete(roster_get_jid_info, + ejabberd_hooks:delete(roster_get_jid_info, Host, ?MODULE, get_jid_info, 70). - %ejabberd_hooks:delete(remove_user, + %ejabberd_hooks:delete(remove_user, Host, % ?MODULE, remove_user, 50), diff --git a/src/mod_stats.erl b/src/mod_stats.erl index 41d0b303c..f379b295f 100644 --- a/src/mod_stats.erl +++ b/src/mod_stats.erl @@ -12,19 +12,19 @@ -behaviour(gen_mod). --export([start/1, - stop/0, +-export([start/2, + stop/1, process_local_iq/3]). -include("jlib.hrl"). -start(Opts) -> +start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_STATS, + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_STATS, ?MODULE, process_local_iq, IQDisc). -stop() -> - gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_STATS). +stop(Host) -> + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_STATS). process_local_iq(From, To, #iq{id = ID, type = Type, diff --git a/src/mod_time.erl b/src/mod_time.erl index ee75533d0..7ad13ad63 100644 --- a/src/mod_time.erl +++ b/src/mod_time.erl @@ -12,21 +12,21 @@ -behaviour(gen_mod). --export([start/1, - stop/0, +-export([start/2, + stop/1, process_local_iq/3]). -include("ejabberd.hrl"). -include("jlib.hrl"). -start(Opts) -> +start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_TIME, + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_TIME, ?MODULE, process_local_iq, IQDisc). -stop() -> - gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_TIME). +stop(Host) -> + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_TIME). process_local_iq(_From, _To, #iq{type = Type, sub_el = SubEl} = IQ) -> case Type of diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index 7feb5b397..09e010a5b 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -12,7 +12,7 @@ -behaviour(gen_mod). --export([start/1, init/2, stop/0, +-export([start/2, init/2, stop/1, process_local_iq/3, process_sm_iq/3, reindex_vcards/0, @@ -40,8 +40,9 @@ }). -record(vcard, {us, vcard}). +-define(PROCNAME, ejabberd_mod_vcard). -start(Opts) -> +start(Host, Opts) -> mnesia:create_table(vcard, [{disc_only_copies, [node()]}, {attributes, record_info(fields, vcard)}]), mnesia:create_table(vcard_search, @@ -61,17 +62,18 @@ start(Opts) -> mnesia:add_table_index(vcard_search, lorgname), mnesia:add_table_index(vcard_search, lorgunit), - ejabberd_hooks:add(remove_user, + ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 50), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_VCARD, + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_VCARD, ?MODULE, process_local_iq, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_VCARD, + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_VCARD, ?MODULE, process_sm_iq, IQDisc), catch mod_disco:register_sm_feature(?NS_VCARD), Hosts = gen_mod:get_hosts(Opts, "vjud."), Search = gen_mod:get_opt(search, Opts, true), - register(ejabberd_mod_vcard, spawn(?MODULE, init, [Hosts, Search])). + register(gen_mod:get_module_proc(Host, ?PROCNAME), + spawn(?MODULE, init, [Hosts, Search])). init(Hosts, Search) -> @@ -100,14 +102,15 @@ loop(Hosts) -> loop(Hosts) end. -stop() -> - ejabberd_hooks:delete(remove_user, +stop(Host) -> + ejabberd_hooks:delete(remove_user, Host, ?MODULE, remove_user, 50), - gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_VCARD), - gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_VCARD), - catch mod_disco:unregister_sm_feature(?NS_VCARD), - ejabberd_mod_vcard ! stop, - ok. + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_VCARD), + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_VCARD), + catch mod_disco:unregister_sm_feature(Host, ?NS_VCARD), + Proc = gen_mod:get_module_proc(Host, ?PROCNAME), + Proc ! stop, + {wait, Proc}. process_local_iq(_From, _To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> case Type of @@ -463,7 +466,8 @@ record_to_item(R) -> search(LServer, Data) -> MatchSpec = make_matchspec(LServer, Data), - AllowReturnAll = gen_mod:get_module_opt(?MODULE, allow_return_all, false), + AllowReturnAll = gen_mod:get_module_opt(LServer, ?MODULE, + allow_return_all, false), if (MatchSpec == #vcard_search{_ = '_'}) and (not AllowReturnAll) -> []; @@ -474,7 +478,8 @@ search(LServer, Data) -> ?ERROR_MSG("~p", [Reason]), []; Rs -> - case gen_mod:get_module_opt(?MODULE, matches, ?JUD_MATCHES) of + case gen_mod:get_module_opt(LServer, ?MODULE, + matches, ?JUD_MATCHES) of infinity -> Rs; Val when is_integer(Val) and (Val > 0) -> @@ -501,8 +506,8 @@ filter_fields([{SVar, [Val]} | Ds], Match, LServer) LVal = stringprep:tolower(Val), NewMatch = case SVar of "user" -> - case gen_mod:get_module_opt( - ?MODULE, search_all_hosts, true) of + case gen_mod:get_module_opt(LServer, ?MODULE, + search_all_hosts, true) of true -> Match#vcard_search{luser = make_val(LVal)}; false -> diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl index 46b5c86e0..9c8149cf6 100644 --- a/src/mod_vcard_ldap.erl +++ b/src/mod_vcard_ldap.erl @@ -12,7 +12,7 @@ -behaviour(gen_mod). --export([start/1, init/2, stop/0, +-export([start/2, init/2, stop/1, process_local_iq/3, process_sm_iq/3, remove_user/1]). @@ -22,11 +22,11 @@ -include("jlib.hrl"). -start(Opts) -> +start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_VCARD, + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_VCARD, ?MODULE, process_local_iq, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_VCARD, + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_VCARD, ?MODULE, process_sm_iq, IQDisc), LDAPServers = ejabberd_config:get_local_option(ldap_servers), RootDN = ejabberd_config:get_local_option(ldap_rootdn), @@ -62,9 +62,9 @@ loop(Host) -> loop(Host) end. -stop() -> - gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_VCARD), - gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_VCARD), +stop(Host) -> + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_VCARD), + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_VCARD), ejabberd_mod_vcard_ldap ! stop, ok. diff --git a/src/mod_version.erl b/src/mod_version.erl index 1912d058c..c62e27a0d 100644 --- a/src/mod_version.erl +++ b/src/mod_version.erl @@ -12,8 +12,8 @@ -behaviour(gen_mod). --export([start/1, - stop/0, +-export([start/2, + stop/1, process_local_iq/3]). -include("ejabberd.hrl"). @@ -21,13 +21,13 @@ -start(Opts) -> +start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_VERSION, + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_VERSION, ?MODULE, process_local_iq, IQDisc). -stop() -> - gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_VERSION). +stop(Host) -> + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_VERSION). process_local_iq(From, To, #iq{id = ID, type = Type, diff --git a/src/web/ejabberd_web.erl b/src/web/ejabberd_web.erl index 3f2867507..70f6e3ee7 100644 --- a/src/web/ejabberd_web.erl +++ b/src/web/ejabberd_web.erl @@ -51,17 +51,46 @@ make_xhtml(Els) -> process_get({_, true}, #request{us = US, + path = ["admin", "server", SHost | RPath], + q = Query, + lang = Lang} = Request) -> + Host = jlib:nameprep(SHost), + case lists:member(Host, ?MYHOSTS) of + true -> + case US of + {User, Server} -> + case acl:match_rule( + Host, configure, jlib:make_jid(User, Server, "")) of + deny -> + {401, [], make_xhtml([?XC("h1", "Not Allowed")])}; + allow -> + ejabberd_web_admin:process_admin( + Host, Request#request{path = RPath}) + end; + undefined -> + {401, + [{"WWW-Authenticate", "basic realm=\"ejabberd\""}], + ejabberd_web:make_xhtml([{xmlelement, "h1", [], + [{xmlcdata, "401 Unauthorized"}]}])} + end; + false -> + {404, [], make_xhtml([?XC("h1", "Not found")])} + end; + +process_get({_, true}, + #request{us = US, path = ["admin" | RPath], q = Query, lang = Lang} = Request) -> case US of {User, Server} -> - case acl:match_rule(configure, jlib:make_jid(User, Server, "")) of + case acl:match_rule( + global, configure, jlib:make_jid(User, Server, "")) of deny -> {401, [], make_xhtml([?XC("h1", "Not Allowed")])}; allow -> ejabberd_web_admin:process_admin( - Request#request{path = RPath}) + global, Request#request{path = RPath}) end; undefined -> {401, diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index 354dc2d0a..8da73fd5c 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -14,7 +14,7 @@ -vsn('$Revision$ '). %% External exports --export([process_admin/1]). +-export([process_admin/2]). -include("ejabberd.hrl"). -include("jlib.hrl"). @@ -52,7 +52,7 @@ {"size", Size}])). -define(INPUTST(Type, Name, Value, Size), ?INPUT(Type, Name, ?T(Value), Size)). -make_xhtml(Els, Lang) -> +make_xhtml(Els, global, Lang) -> {200, [html], {xmlelement, "html", [{"xmlns", "http://www.w3.org/1999/xhtml"}, {"xml:lang", Lang}, @@ -76,16 +76,60 @@ make_xhtml(Els, Lang) -> [?XE("ul", [?LI([?ACT("/admin/acls/", "Access Control Lists")]), ?LI([?ACT("/admin/access/", "Access Rules")]), - ?LI([?ACT("/admin/users/", "Users")]), - ?LI([?ACT("/admin/online-users/", "Online Users")]), - ?LI([?ACT("/admin/last-activity/", "Last Activity")]), ?LI([?ACT("/admin/nodes/", "Nodes")]), ?LI([?ACT("/admin/stats/", "Statistics")]) + ] + )]), + ?XAE("div", + [{"id", "content"}], + Els), + ?XAE("div", + [{"id", "clearcopyright"}], + [{xmlcdata, ""}])]), + ?XAE("div", + [{"id", "copyrightouter"}], + [?XAE("div", + [{"id", "copyright"}], + [?XCT("p", + "ejabberd (c) 2002-2005 Alexey Shchepin, 2004-2005 Process One") + ])])]) + ]}}; + +make_xhtml(Els, Host, Lang) -> + Base = "/admin/server/" ++ Host ++ "/", + {200, [html], + {xmlelement, "html", [{"xmlns", "http://www.w3.org/1999/xhtml"}, + {"xml:lang", Lang}, + {"lang", Lang}], + [{xmlelement, "head", [], + [{xmlelement, "meta", [{"http-equiv", "Content-Type"}, + {"content", "text/html; charset=utf-8"}], []}, + {xmlelement, "link", [{"href", Base ++ "style.css"}, + {"type", "text/css"}, + {"rel", "stylesheet"}], []}]}, + ?XE("body", + [?XAE("div", + [{"id", "container"}], + [?XAE("div", + [{"id", "header"}], + [?XE("h1", + [?ACT(Base, "ejabberd administration")] + )]), + ?XAE("div", + [{"id", "navigation"}], + [?XE("ul", + [?LI([?ACT(Base ++ "acls/", "Access Control Lists")]), + ?LI([?ACT(Base ++ "access/", "Access Rules")]), + ?LI([?ACT(Base ++ "users/", "Users")]), + ?LI([?ACT(Base ++ "online-users/", "Online Users")]), + ?LI([?ACT(Base ++ "last-activity/", "Last Activity")]), + ?LI([?ACT(Base ++ "nodes/", "Nodes")]), + ?LI([?ACT(Base ++ "stats/", "Statistics")]) ] ++ case lists:member(mod_shared_roster, - gen_mod:loaded_modules()) of + gen_mod:loaded_modules(Host)) of true -> - [?LI([?ACT("/admin/shared-roster/", "Shared Roster")])]; + [?LI([?ACT(Base ++ "shared-roster/", "Shared Roster")])]; false -> [] end @@ -105,7 +149,14 @@ make_xhtml(Els, Lang) -> ])])]) ]}}. -css() -> " +css(Host) -> + Base = case Host of + global -> + "/admin/"; + _ -> + "/admin/server/" ++ Host ++ "/" + end, + " html,body { background: white; margin: 0; @@ -130,7 +181,7 @@ html>body #container { height: 55px; padding: 0; margin: 0; - background: transparent url(\"/admin/logo-fill.png\"); + background: transparent url(\"" ++ Base ++ "logo-fill.png\"); } #header h1 a { @@ -141,7 +192,7 @@ html>body #container { height: 55px; padding: 0; margin: 0; - background: transparent url(\"/admin/logo.png\") no-repeat; + background: transparent url(\"" ++ Base ++ "logo.png\") no-repeat; display: block; text-indent: -700em; } @@ -466,7 +517,8 @@ logo_fill() -> "1c5dvhSU2BpKqBXl6R0ljYGS50R5zVC+tVD+vfE6YyUexE9x7g4AAAAASUVO" "RK5CYII="). -process_admin(#request{us = US, +process_admin(global, + #request{us = US, path = [], q = Query, lang = Lang} = Request) -> @@ -476,41 +528,63 @@ process_admin(#request{us = US, ?ACT("/admin/acls-raw/", "(raw)")]), ?LI([?ACT("/admin/access/", "Access Rules"), ?C(" "), ?ACT("/admin/access-raw/", "(raw)")]), - ?LI([?ACT("/admin/users/", "Users")]), - ?LI([?ACT("/admin/online-users/", "Online Users")]), - ?LI([?ACT("/admin/last-activity/", "Last Activity")]), ?LI([?ACT("/admin/nodes/", "Nodes")]), ?LI([?ACT("/admin/stats/", "Statistics")]) + ] + ) + ], global, Lang); + +process_admin(Host, + #request{us = US, + path = [], + q = Query, + lang = Lang} = Request) -> + Base = "/admin/server/" ++ Host ++ "/", + make_xhtml([?XCT("h1", "ejabberd administration"), + ?XE("ul", + [?LI([?ACT(Base ++ "acls/", "Access Control Lists"), ?C(" "), + ?ACT(Base ++ "acls-raw/", "(raw)")]), + ?LI([?ACT(Base ++ "access/", "Access Rules"), ?C(" "), + ?ACT(Base ++ "access-raw/", "(raw)")]), + ?LI([?ACT(Base ++ "users/", "Users")]), + ?LI([?ACT(Base ++ "online-users/", "Online Users")]), + ?LI([?ACT(Base ++ "last-activity/", "Last Activity")]), + ?LI([?ACT(Base ++ "nodes/", "Nodes")]), + ?LI([?ACT(Base ++ "stats/", "Statistics")]) ] ++ case lists:member(mod_shared_roster, - gen_mod:loaded_modules()) of + gen_mod:loaded_modules(Host)) of true -> - [?LI([?ACT("/admin/shared-roster/", "Shared Roster")])]; + [?LI([?ACT(Base ++ "shared-roster/", "Shared Roster")])]; false -> [] end ) - ], Lang); + ], Host, Lang); -process_admin(#request{us = US, +process_admin(Host, + #request{us = US, path = ["style.css"], q = Query, lang = Lang} = Request) -> - {200, [{"Content-Type", "text/css"}], css()}; + {200, [{"Content-Type", "text/css"}], css(Host)}; -process_admin(#request{us = US, +process_admin(Host, + #request{us = US, path = ["logo.png"], q = Query, lang = Lang} = Request) -> {200, [{"Content-Type", "image/png"}], logo()}; -process_admin(#request{us = US, +process_admin(Host, + #request{us = US, path = ["logo-fill.png"], q = Query, lang = Lang} = Request) -> {200, [{"Content-Type", "image/png"}], logo_fill()}; -process_admin(#request{us = US, +process_admin(Host, + #request{us = US, path = ["acls-raw"], q = Query, lang = Lang} = Request) -> @@ -520,7 +594,7 @@ process_admin(#request{us = US, {ok, Tokens, _} -> case erl_parse:parse_term(Tokens) of {ok, NewACLs} -> - case acl:add_list(NewACLs, true) of + case acl:add_list(Host, NewACLs, true) of ok -> ok; _ -> @@ -535,7 +609,11 @@ process_admin(#request{us = US, _ -> nothing end, - ACLs = lists:flatten(io_lib:format("~p.", [ets:tab2list(acl)])), + ACLs = lists:flatten( + io_lib:format( + "~p.", [lists:keysort( + 2, ets:select(acl, [{{acl, {'$1', Host}, '$2'}, + [], [{{acl, '$1', '$2'}}]}]))])), make_xhtml([?XCT("h1", "ejabberd access control lists configuration")] ++ case Res of ok -> [?CT("submitted"), ?P]; @@ -550,9 +628,10 @@ process_admin(#request{us = US, ?BR, ?INPUTT("submit", "submit", "Submit") ]) - ], Lang); + ], Host, Lang); -process_admin(#request{method = Method, +process_admin(Host, + #request{method = Method, us = US, path = ["acls"], q = Query, @@ -560,12 +639,12 @@ process_admin(#request{method = Method, ?INFO_MSG("query: ~p", [Query]), Res = case Method of 'POST' -> - case catch acl_parse_query(Query) of + case catch acl_parse_query(Host, Query) of {'EXIT', _} -> error; NewACLs -> - ?INFO_MSG("NewACLs: ~p", [NewACLs]), - case acl:add_list(NewACLs, true) of + ?INFO_MSG("NewACLs at ~s: ~p", [Host, NewACLs]), + case acl:add_list(Host, NewACLs, true) of ok -> ?INFO_MSG("NewACLs: ok", []), ok; @@ -576,7 +655,9 @@ process_admin(#request{method = Method, _ -> nothing end, - ACLs = lists:keysort(2, ets:tab2list(acl)), + ACLs = lists:keysort( + 2, ets:select(acl, [{{acl, {'$1', Host}, '$2'}, + [], [{{acl, '$1', '$2'}}]}])), make_xhtml([?XCT("h1", "ejabberd access control lists configuration")] ++ case Res of ok -> [?CT("submitted"), ?P]; @@ -591,9 +672,10 @@ process_admin(#request{method = Method, ?C(" "), ?INPUTT("submit", "submit", "Submit") ]) - ], Lang); + ], Host, Lang); -process_admin(#request{us = US, +process_admin(Host, + #request{us = US, path = ["access-raw"], q = Query, lang = Lang} = Request) -> @@ -601,17 +683,18 @@ process_admin(#request{us = US, fun(Rs) -> mnesia:transaction( fun() -> - Os = mnesia:select(config, - [{{config, {access, '$1'}, '$2'}, - [], - ['$_']}]), + Os = mnesia:select( + config, + [{{config, {access, '$1', Host}, '$2'}, + [], + ['$_']}]), lists:foreach(fun(O) -> mnesia:delete_object(O) end, Os), lists:foreach( fun({access, Name, Rules}) -> mnesia:write({config, - {access, Name}, + {access, Name, Host}, Rules}) end, Rs) end) @@ -641,7 +724,7 @@ process_admin(#request{us = US, lists:flatten( io_lib:format( "~p.", [ets:select(config, - [{{config, {access, '$1'}, '$2'}, + [{{config, {access, '$1', Host}, '$2'}, [], [{{access, '$1', '$2'}}]}])])), make_xhtml([?XCT("h1", "ejabberd access rules configuration")] ++ @@ -658,9 +741,10 @@ process_admin(#request{us = US, ?BR, ?INPUTT("submit", "submit", "Submit") ]) - ], Lang); + ], Host, Lang); -process_admin(#request{method = Method, +process_admin(Host, + #request{method = Method, us = US, path = ["access"], q = Query, @@ -668,7 +752,7 @@ process_admin(#request{method = Method, ?INFO_MSG("query: ~p", [Query]), Res = case Method of 'POST' -> - case catch access_parse_query(Query) of + case catch access_parse_query(Host, Query) of {'EXIT', _} -> error; ok -> @@ -679,7 +763,7 @@ process_admin(#request{method = Method, end, AccessRules = ets:select(config, - [{{config, {access, '$1'}, '$2'}, + [{{config, {access, '$1', Host}, '$2'}, [], [{{access, '$1', '$2'}}]}]), make_xhtml([?XCT("h1", "ejabberd access rules configuration")] ++ @@ -694,9 +778,10 @@ process_admin(#request{method = Method, ?BR, ?INPUTT("submit", "delete", "Delete Selected") ]) - ], Lang); + ], Host, Lang); -process_admin(#request{method = Method, +process_admin(Host, + #request{method = Method, us = US, path = ["access", SName], q = Query, @@ -708,7 +793,7 @@ process_admin(#request{method = Method, case parse_access_rule(String) of {ok, Rs} -> ejabberd_config:add_global_option( - {access, Name}, Rs), + {access, Name, Host}, Rs), ok; _ -> error @@ -716,7 +801,7 @@ process_admin(#request{method = Method, _ -> nothing end, - Rules = case ejabberd_config:get_global_option({access, Name}) of + Rules = case ejabberd_config:get_global_option({access, Name, Host}) of undefined -> []; Rs1 -> @@ -734,34 +819,38 @@ process_admin(#request{method = Method, ?BR, ?INPUTT("submit", "submit", "Submit") ]) - ], Lang); + ], Host, Lang); -process_admin(#request{us = US, +process_admin(Host, + #request{us = US, path = ["users"], q = Query, - lang = Lang} = Request) -> - Res = list_users(Query, Lang), - make_xhtml([?XCT("h1", "ejabberd users")] ++ Res, Lang); + lang = Lang} = Request) when is_list(Host) -> + Res = list_users(Host, Query, Lang), + make_xhtml([?XCT("h1", "ejabberd users")] ++ Res, Host, Lang); -process_admin(#request{us = US, +process_admin(Host, + #request{us = US, path = ["users", Diap], q = Query, - lang = Lang} = Request) -> - Res = list_users_in_diapason(Diap, Lang), - make_xhtml([?XCT("h1", "ejabberd users")] ++ Res, Lang); + lang = Lang} = Request) when is_list(Host) -> + Res = list_users_in_diapason(Host, Diap, Lang), + make_xhtml([?XCT("h1", "ejabberd users")] ++ Res, Host, Lang); -process_admin(#request{us = US, +process_admin(Host, + #request{us = US, path = ["online-users"], q = Query, - lang = Lang} = Request) -> - Res = list_online_users(Lang), - make_xhtml([?XCT("h1", "ejabberd users")] ++ Res, Lang); + lang = Lang} = Request) when is_list(Host) -> + Res = list_online_users(Host, Lang), + make_xhtml([?XCT("h1", "ejabberd users")] ++ Res, Host, Lang); -process_admin(#request{method = Method, +process_admin(Host, + #request{method = Method, us = US, path = ["last-activity"], q = Query, - lang = Lang} = Request) -> + lang = Lang} = Request) when is_list(Host) -> ?INFO_MSG("query: ~p", [Query]), Month = case lists:keysearch("period", 1, Query) of {value, {_, Val}} -> @@ -771,9 +860,9 @@ process_admin(#request{method = Method, end, Res = case lists:keysearch("ordinary", 1, Query) of {value, {_, _}} -> - list_last_activity(Lang, false, Month); + list_last_activity(Host, Lang, false, Month); _ -> - list_last_activity(Lang, true, Month) + list_last_activity(Host, Lang, true, Month) end, make_xhtml([?XCT("h1", "Users last activity")] ++ [?XAE("form", [{"method", "post"}], @@ -795,71 +884,80 @@ process_admin(#request{method = Method, ?C(" "), ?INPUTT("submit", "integral", "Show Integral Table") ])] ++ - Res, Lang); + Res, Host, Lang); -process_admin(#request{us = US, +process_admin(Host, + #request{us = US, path = ["stats"], q = Query, lang = Lang} = Request) -> - Res = get_stats(Lang), - make_xhtml([?XCT("h1", "ejabberd stats")] ++ Res, Lang); + Res = get_stats(Host, Lang), + make_xhtml([?XCT("h1", "ejabberd stats")] ++ Res, Host, Lang); -process_admin(#request{us = US, +process_admin(Host, + #request{us = US, path = ["user", U], q = Query, lang = Lang} = Request) -> - Res = user_info(U, Query, Lang), - make_xhtml(Res, Lang); + Res = user_info(U, Host, Query, Lang), + make_xhtml(Res, Host, Lang); -process_admin(#request{us = US, +process_admin(Host, + #request{us = US, path = ["user", U, "queue"], q = Query, lang = Lang} = Request) -> - Res = user_queue(U, Query, Lang), - make_xhtml(Res, Lang); + Res = user_queue(U, Host, Query, Lang), + make_xhtml(Res, Host, Lang); -process_admin(#request{us = US, +process_admin(Host, + #request{us = US, path = ["user", U, "roster"], q = Query, lang = Lang} = Request) -> - Res = user_roster(U, Query, Lang, true), - make_xhtml(Res, Lang); + Res = user_roster(U, Host, Query, Lang, true), + make_xhtml(Res, Host, Lang); -process_admin(#request{us = US, +process_admin(Host, + #request{us = US, path = ["nodes"], q = Query, lang = Lang} = Request) -> Res = get_nodes(Lang), - make_xhtml(Res, Lang); + make_xhtml(Res, Host, Lang); -process_admin(#request{us = US, +process_admin(Host, + #request{us = US, path = ["node", SNode | NPath], q = Query, lang = Lang} = Request) -> case search_running_node(SNode) of false -> - make_xhtml([?XCT("h1", "Node not found")], Lang); + make_xhtml([?XCT("h1", "Node not found")], Host, Lang); Node -> - Res = get_node(Node, NPath, Query, Lang), - make_xhtml(Res, Lang) + Res = get_node(Host, Node, NPath, Query, Lang), + make_xhtml(Res, Host, Lang) end; -process_admin(#request{us = US, +process_admin(Host, + #request{us = US, path = ["shared-roster"], q = Query, lang = Lang} = Request) -> Res = list_shared_roster_groups(Query, Lang), - make_xhtml(Res, Lang); + make_xhtml(Res, Host, Lang); -process_admin(#request{us = US, +process_admin(Host, + #request{us = US, path = ["shared-roster", Group], q = Query, lang = Lang} = Request) -> Res = shared_roster_group(Group, Query, Lang), - make_xhtml(Res, Lang); + make_xhtml(Res, Host, Lang); -process_admin(#request{lang = Lang}) -> - setelement(1, make_xhtml([?XC("h1", "Not found")], Lang), 404). +process_admin(Host, + #request{lang = Lang}) -> + setelement(1, make_xhtml([?XC("h1", "Not found")], Host, Lang), 404). @@ -924,8 +1022,9 @@ term_to_id(T) -> jlib:encode_base64(binary_to_list(term_to_binary(T))). -acl_parse_query(Query) -> - ACLs = ets:tab2list(acl), +acl_parse_query(Host, Query) -> + ACLs = ets:select(acl, [{{acl, {'$1', Host}, '$2'}, + [], [{{acl, '$1', '$2'}}]}]), case lists:keysearch("submit", 1, Query) of {value, _} -> acl_parse_submit(ACLs, Query); @@ -977,7 +1076,7 @@ string_to_spec("server", Val) -> {server, Val}; string_to_spec("user_server", Val) -> #jid{luser = U, lserver = S, resource = ""} = jlib:string_to_jid(Val), - {user_server, U, S}; + {user, U, S}; string_to_spec("raw", Val) -> {ok, Tokens, _} = erl_scan:string(Val ++ "."), {ok, NewSpec} = erl_parse:parse_term(Tokens), @@ -1016,31 +1115,31 @@ access_rules_to_xhtml(AccessRules, Lang) -> )] )]). -access_parse_query(Query) -> +access_parse_query(Host, Query) -> AccessRules = ets:select(config, - [{{config, {access, '$1'}, '$2'}, + [{{config, {access, '$1', Host}, '$2'}, [], [{{access, '$1', '$2'}}]}]), case lists:keysearch("addnew", 1, Query) of {value, _} -> - access_parse_addnew(AccessRules, Query); + access_parse_addnew(AccessRules, Host, Query); _ -> case lists:keysearch("delete", 1, Query) of {value, _} -> - access_parse_delete(AccessRules, Query) + access_parse_delete(AccessRules, Host, Query) end end. -access_parse_addnew(AccessRules, Query) -> +access_parse_addnew(AccessRules, Host, Query) -> case lists:keysearch("namenew", 1, Query) of {value, {_, String}} when String /= "" -> Name = list_to_atom(String), - ejabberd_config:add_global_option({access, Name}, []), + ejabberd_config:add_global_option({access, Name, Host}, []), ok end. -access_parse_delete(AccessRules, Query) -> +access_parse_delete(AccessRules, Host, Query) -> lists:foreach( fun({access, Name, _Rules} = AccessRule) -> ID = term_to_id(AccessRule), @@ -1048,7 +1147,7 @@ access_parse_delete(AccessRules, Query) -> true -> mnesia:transaction( fun() -> - mnesia:delete({config, {access, Name}}) + mnesia:delete({config, {access, Name, Host}}) end); _ -> ok @@ -1091,9 +1190,9 @@ parse_access_rule(Text) -> -list_users(Query, Lang) -> +list_users(Host, Query, Lang) -> Res = list_users_parse_query(Query), - Users = ejabberd_auth:dirty_get_registered_users(), + Users = ejabberd_auth:get_vh_registered_users(Host), SUsers = lists:sort([{S, U} || {U, S} <- Users]), FUsers = case length(SUsers) of @@ -1162,8 +1261,8 @@ list_users_parse_query(Query) -> end. -list_users_in_diapason(Diap, Lang) -> - Users = ejabberd_auth:dirty_get_registered_users(), +list_users_in_diapason(Host, Diap, Lang) -> + Users = ejabberd_auth:get_vh_registered_users(Host), SUsers = lists:sort([{S, U} || {U, S} <- Users]), {ok, [S1, S2]} = regexp:split(Diap, "-"), N1 = list_to_integer(S1), @@ -1184,7 +1283,7 @@ list_given_users(Users, Prefix, Lang) -> US = {User, Server}, QueueLen = length(mnesia:dirty_read({offline_msg, US})), FQueueLen = [?AC(Prefix ++ "user/" ++ - User ++ "@" ++ Server ++ "/queue/", + User ++ "/queue/", integer_to_list(QueueLen))], FLast = case ejabberd_sm:get_user_resources(User, Server) of @@ -1208,8 +1307,7 @@ list_given_users(Users, Prefix, Lang) -> ?T("Online") end, ?XE("tr", - [?XE("td", [?AC(Prefix ++ "user/" ++ - us_to_list(US) ++ "/", + [?XE("td", [?AC(Prefix ++ "user/" ++ User ++ "/", us_to_list(US))]), ?XE("td", FQueueLen), ?XC("td", FLast)]) @@ -1223,14 +1321,13 @@ su_to_list({Server, User}) -> jlib:jid_to_string({User, Server, ""}). -get_stats(Lang) -> +get_stats(global, Lang) -> OnlineUsers = mnesia:table_info(presence, size), AuthUsers = mnesia:table_info(session, size), RegisteredUsers = mnesia:table_info(passwd, size), S2SConns = ejabberd_s2s:dirty_get_connections(), S2SConnections = length(S2SConns), S2SServers = length(lists:usort([element(2, C) || C <- S2SConns])), - [?XAE("table", [], [?XE("tbody", [?XE("tr", [?XCT("td", "Registered users"), @@ -1244,22 +1341,31 @@ get_stats(Lang) -> ?XE("tr", [?XCT("td", "Outgoing S2S servers"), ?XC("td", integer_to_list(S2SServers))]) ]) + ])]; + +get_stats(Host, Lang) -> + OnlineUsers = length(ejabberd_sm:get_vh_session_list(Host)), + RegisteredUsers = length(ejabberd_auth:get_vh_registered_users(Host)), + [?XAE("table", [], + [?XE("tbody", + [?XE("tr", [?XCT("td", "Registered users"), + ?XC("td", integer_to_list(RegisteredUsers))]), + ?XE("tr", [?XCT("td", "Online users"), + ?XC("td", integer_to_list(OnlineUsers))]) + ]) ])]. -list_online_users(_Lang) -> - Users = [{S, U} || {U, S, R} <- ejabberd_sm:dirty_get_sessions_list()], +list_online_users(Host, _Lang) -> + Users = [{S, U} || {U, S, R} <- ejabberd_sm:get_vh_session_list(Host)], SUsers = lists:usort(Users), lists:flatmap( - fun(SU) -> - [?AC("../user/" ++ su_to_list(SU) ++ "/", su_to_list(SU)), ?BR] + fun({S, U} = SU) -> + [?AC("../user/" ++ U ++ "/", su_to_list(SU)), ?BR] end, SUsers). -user_info(SUser, Query, Lang) -> - UJID = jlib:string_to_jid(SUser), - User = UJID#jid.user, - Server = UJID#jid.server, - US = {UJID#jid.luser, UJID#jid.lserver}, +user_info(User, Server, Query, Lang) -> + US = {jlib:nodeprep(User), jlib:nameprep(Server)}, Res = user_parse_query(User, Server, Query), Resources = ejabberd_sm:get_user_resources(User, Server), FResources = @@ -1315,11 +1421,8 @@ user_parse_query(User, Server, Query) -> end. -user_queue(SUser, Query, Lang) -> - UJID = jlib:string_to_jid(SUser), - User = UJID#jid.user, - Server = UJID#jid.server, - US = {UJID#jid.luser, UJID#jid.lserver}, +user_queue(User, Server, Query, Lang) -> + US = {jlib:nodeprep(User), jlib:nameprep(Server)}, Res = user_queue_parse_query(US, Query), Msgs = lists:keysort(3, mnesia:dirty_read({offline_msg, US})), FMsgs = @@ -1409,11 +1512,8 @@ ask_to_pending(unsubscribe) -> none; ask_to_pending(Ask) -> Ask. -user_roster(SUser, Query, Lang, Admin) -> - UJID = jlib:string_to_jid(SUser), - User = UJID#jid.user, - Server = UJID#jid.server, - US = {UJID#jid.luser, UJID#jid.lserver}, +user_roster(User, Server, Query, Lang, Admin) -> + US = {jlib:nodeprep(User), jlib:nameprep(Server)}, Items1 = mnesia:dirty_index_read(roster, US, #roster.us), Res = user_roster_parse_query(User, Server, Items1, Query, Admin), Items = mnesia:dirty_index_read(roster, US, #roster.us), @@ -1556,7 +1656,7 @@ user_roster_item_parse_query(User, Server, Items, Query) -> nothing. -list_last_activity(Lang, Integral, Period) -> +list_last_activity(Host, Lang, Integral, Period) -> {MegaSecs, Secs, _MicroSecs} = now(), TimeStamp = MegaSecs * 1000000 + Secs, case Period of @@ -1571,7 +1671,7 @@ list_last_activity(Lang, Integral, Period) -> Days = 31 end, case catch mnesia:dirty_select( - last_activity, [{{last_activity, '_', '$1', '_'}, + last_activity, [{{last_activity, {'_', Host}, '$1', '_'}, [{'>', '$1', TS}], [{'trunc', {'/', {'-', TimeStamp, '$1'}, @@ -1677,7 +1777,7 @@ search_running_node(SNode, [Node | Nodes]) -> search_running_node(SNode, Nodes) end. -get_node(Node, [], Query, Lang) -> +get_node(global, Node, [], Query, Lang) -> Res = node_parse_query(Node, Query), [?XC("h1", ?T("Node ") ++ atom_to_list(Node))] ++ case Res of @@ -1689,7 +1789,6 @@ get_node(Node, [], Query, Lang) -> [?LI([?ACT("db/", "DB Management")]), ?LI([?ACT("backup/", "Backup Management")]), ?LI([?ACT("ports/", "Listened Ports Management")]), - ?LI([?ACT("modules/", "Modules Management")]), ?LI([?ACT("stats/", "Statistics")]) ]), ?XAE("form", [{"method", "post"}], @@ -1698,7 +1797,13 @@ get_node(Node, [], Query, Lang) -> ?INPUTT("submit", "stop", "Stop")]) ]; -get_node(Node, ["db"], Query, Lang) -> +get_node(Host, Node, [], Query, Lang) -> + [?XC("h1", ?T("Node ") ++ atom_to_list(Node)), + ?XE("ul", + [?LI([?ACT("modules/", "Modules Management")])]) + ]; + +get_node(global, Node, ["db"], Query, Lang) -> case rpc:call(Node, mnesia, system_info, [tables]) of {badrpc, _Reason} -> [?XCT("h1", "RPC call error")]; @@ -1765,7 +1870,7 @@ get_node(Node, ["db"], Query, Lang) -> )])])] end; -get_node(Node, ["backup"], Query, Lang) -> +get_node(global, Node, ["backup"], Query, Lang) -> Res = node_backup_parse_query(Node, Query), [?XC("h1", ?T("Backup Management at ") ++ atom_to_list(Node)), ?XAE("form", [{"method", "post"}], @@ -1810,7 +1915,7 @@ get_node(Node, ["backup"], Query, Lang) -> ]) ])])]; -get_node(Node, ["ports"], Query, Lang) -> +get_node(global, Node, ["ports"], Query, Lang) -> Ports = rpc:call(Node, ejabberd_config, get_local_option, [listen]), Res = case catch node_ports_parse_query(Node, Ports, Query) of submitted -> @@ -1832,9 +1937,9 @@ get_node(Node, ["ports"], Query, Lang) -> [node_ports_to_xhtml(NewPorts, Lang)]) ]; -get_node(Node, ["modules"], Query, Lang) -> +get_node(Host, Node, ["modules"], Query, Lang) when is_list(Host) -> Modules = rpc:call(Node, gen_mod, loaded_modules_with_opts, []), - Res = case catch node_modules_parse_query(Node, Modules, Query) of + Res = case catch node_modules_parse_query(Host, Node, Modules, Query) of submitted -> ok; {'EXIT', Reason} -> @@ -1843,7 +1948,8 @@ get_node(Node, ["modules"], Query, Lang) -> _ -> nothing end, - NewModules = lists:sort(rpc:call(Node, gen_mod, loaded_modules_with_opts, [])), + NewModules = lists:sort( + rpc:call(Node, gen_mod, loaded_modules_with_opts, [Host])), [?XC("h1", ?T("Modules at ") ++ atom_to_list(Node))] ++ case Res of ok -> [?CT("submitted"), ?P]; @@ -1854,7 +1960,7 @@ get_node(Node, ["modules"], Query, Lang) -> [node_modules_to_xhtml(NewModules, Lang)]) ]; -get_node(Node, ["stats"], Query, Lang) -> +get_node(global, Node, ["stats"], Query, Lang) -> UpTime = rpc:call(Node, erlang, statistics, [wall_clock]), UpTimeS = io_lib:format("~.3f", [element(1, UpTime)/1000]), CPUTime = rpc:call(Node, erlang, statistics, [runtime]), @@ -1897,7 +2003,7 @@ get_node(Node, ["stats"], Query, Lang) -> ]) ])]; -get_node(Node, NPath, Query, Lang) -> +get_node(Host, Node, NPath, Query, Lang) -> [?XCT("h1", "Not found")]. @@ -2133,7 +2239,7 @@ node_modules_to_xhtml(Modules, Lang) -> )] )]). -node_modules_parse_query(Node, Modules, Query) -> +node_modules_parse_query(Host, Node, Modules, Query) -> lists:foreach( fun({Module, _Opts1}) -> SModule = atom_to_list(Module), @@ -2143,13 +2249,13 @@ node_modules_parse_query(Node, Modules, Query) -> lists:keysearch("opts" ++ SModule, 1, Query), {ok, Tokens, _} = erl_scan:string(SOpts ++ "."), {ok, Opts} = erl_parse:parse_term(Tokens), - rpc:call(Node, gen_mod, stop_module, [Module]), - rpc:call(Node, gen_mod, start_module, [Module, Opts]), + rpc:call(Node, gen_mod, stop_module, [Host, Module]), + rpc:call(Node, gen_mod, start_module, [Host, Module, Opts]), throw(submitted); _ -> case lists:keysearch("stop" ++ SModule, 1, Query) of {value, _} -> - rpc:call(Node, gen_mod, stop_module, [Module]), + rpc:call(Node, gen_mod, stop_module, [Host, Module]), throw(submitted); _ -> ok @@ -2165,7 +2271,7 @@ node_modules_parse_query(Node, Modules, Query) -> Module = list_to_atom(SModule), {ok, Tokens, _} = erl_scan:string(SOpts ++ "."), {ok, Opts} = erl_parse:parse_term(Tokens), - rpc:call(Node, gen_mod, start_module, [Module, Opts]), + rpc:call(Node, gen_mod, start_module, [Host, Module, Opts]), throw(submitted); _ -> ok |