25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-11-22 16:20:52 +01:00

* (all): Enhanced virtual hosting support

SVN Revision: 370
This commit is contained in:
Alexey Shchepin 2005-06-20 03:18:13 +00:00
parent cb90075327
commit 4098c3ecba
41 changed files with 1039 additions and 747 deletions

View File

@ -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> 2005-05-28 Alexey Shchepin <alexey@sevcom.net>
* src/web/ejabberd_web_admin.erl: Bugfix * src/web/ejabberd_web_admin.erl: Bugfix

View File

@ -11,12 +11,12 @@
-vsn('$Revision$ '). -vsn('$Revision$ ').
-export([start/0, -export([start/0,
to_record/2, to_record/3,
add/2, add/3,
add_list/2, add_list/3,
match_rule/2, match_rule/3,
% for debugging only % for debugging only
match_acl/2]). match_acl/3]).
-include("ejabberd.hrl"). -include("ejabberd.hrl").
@ -30,30 +30,35 @@ start() ->
mnesia:add_table_copy(acl, node(), ram_copies), mnesia:add_table_copy(acl, node(), ram_copies),
ok. ok.
to_record(ACLName, ACLSpec) -> to_record(Host, ACLName, ACLSpec) ->
#acl{aclname = ACLName, aclspec = ACLSpec}. #acl{aclname = {ACLName, Host}, aclspec = ACLSpec}.
add(ACLName, ACLSpec) -> add(Host, ACLName, ACLSpec) ->
F = fun() -> F = fun() ->
mnesia:write(#acl{aclname = ACLName, aclspec = ACLSpec}) mnesia:write(#acl{aclname = {ACLName, Host},
aclspec = ACLSpec})
end, end,
mnesia:transaction(F). mnesia:transaction(F).
add_list(ACLs, Clear) -> add_list(Host, ACLs, Clear) ->
F = fun() -> F = fun() ->
if if
Clear -> Clear ->
Ks = mnesia:all_keys(acl), Ks = mnesia:select(
acl, [{{acl, {'$1', Host}, '$2'}, [], ['$1']}]),
lists:foreach(fun(K) -> lists:foreach(fun(K) ->
mnesia:delete({acl, K}) mnesia:delete({acl, {K, Host}})
end, Ks); end, Ks);
true -> true ->
ok ok
end, end,
lists:foreach(fun(ACL) -> lists:foreach(fun(ACL) ->
case ACL of case ACL of
#acl{} -> #acl{aclname = ACLName,
mnesia:write(ACL) aclspec = ACLSpec} ->
mnesia:write(
#acl{aclname = {ACLName, Host},
aclspec = ACLSpec})
end end
end, ACLs) end, ACLs)
end, end,
@ -66,30 +71,53 @@ add_list(ACLs, Clear) ->
match_rule(Rule, JID) -> match_rule(global, Rule, JID) ->
case Rule of case Rule of
all -> allow; all -> allow;
none -> deny; none -> deny;
_ -> _ ->
case ejabberd_config:get_global_option({access, Rule}) of case ejabberd_config:get_global_option({access, Rule, global}) of
undefined ->
deny;
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 -> undefined ->
deny; deny;
ACLs -> ACLs ->
match_acls(ACLs, JID) 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
end. end.
match_acls([], _) -> match_acls([], _, Host) ->
deny; deny;
match_acls([{Access, ACL} | ACLs], JID) -> match_acls([{Access, ACL} | ACLs], JID, Host) ->
case match_acl(ACL, JID) of case match_acl(ACL, JID, Host) of
true -> true ->
Access; Access;
_ -> _ ->
match_acls(ACLs, JID) match_acls(ACLs, JID, Host)
end. end.
match_acl(ACL, JID) -> match_acl(ACL, JID, Host) ->
case ACL of case ACL of
all -> true; all -> true;
none -> false; none -> false;
@ -100,14 +128,20 @@ match_acl(ACL, JID) ->
all -> all ->
true; true;
{user, U} -> {user, U} ->
(U == User) andalso (?MYNAME == Server); (U == User)
andalso
((Host == Server) orelse
((Host == global) andalso
lists:member(Server, ?MYHOSTS)));
{user, U, S} -> {user, U, S} ->
(U == User) andalso (S == Server); (U == User) andalso (S == Server);
{server, S} -> {server, S} ->
S == Server; S == Server;
{user_regexp, UR} -> {user_regexp, UR} ->
(?MYNAME == Server) andalso ((Host == Server) orelse
is_regexp_match(User, UR); ((Host == global) andalso
lists:member(Server, ?MYHOSTS)))
andalso is_regexp_match(User, UR);
{user_regexp, UR, S} -> {user_regexp, UR, S} ->
(S == Server) andalso (S == Server) andalso
is_regexp_match(User, UR); is_regexp_match(User, UR);
@ -117,7 +151,10 @@ match_acl(ACL, JID) ->
is_regexp_match(Server, SR) andalso is_regexp_match(Server, SR) andalso
is_regexp_match(User, UR); is_regexp_match(User, UR);
{user_glob, UR} -> {user_glob, UR} ->
(?MYNAME == Server) andalso ((Host == Server) orelse
((Host == global) andalso
lists:member(Server, ?MYHOSTS)))
andalso
is_glob_match(User, UR); is_glob_match(User, UR);
{user_glob, UR, S} -> {user_glob, UR, S} ->
(S == Server) andalso (S == Server) andalso
@ -128,7 +165,9 @@ match_acl(ACL, JID) ->
is_glob_match(Server, SR) andalso is_glob_match(Server, SR) andalso
is_glob_match(User, UR) is_glob_match(User, UR)
end end
end, ets:lookup(acl, ACL)) end,
ets:lookup(acl, {ACL, global}) ++
ets:lookup(acl, {ACL, Host}))
end. end.
is_regexp_match(String, RegExp) -> is_regexp_match(String, RegExp) ->

View File

@ -87,14 +87,18 @@ db_init() ->
mnesia:wait_for_tables(mnesia:system_info(local_tables), infinity). mnesia:wait_for_tables(mnesia:system_info(local_tables), infinity).
load_modules() -> load_modules() ->
lists:foreach(
fun(Host) ->
case ejabberd_config:get_local_option(modules) of case ejabberd_config:get_local_option(modules) of
undefined -> undefined ->
ok; ok;
Modules -> Modules ->
lists:foreach(fun({Module, Args}) -> lists:foreach(
gen_mod:start_module(Module, Args) fun({Module, Args}) ->
gen_mod:start_module(Host, Module, Args)
end, Modules) end, Modules)
end. end
end, ?MYHOSTS).
dump_ports() -> dump_ports() ->

View File

@ -165,7 +165,7 @@ remove_user(User, Server) ->
mnesia:delete({passwd, US}) mnesia:delete({passwd, US})
end, end,
mnesia:transaction(F), mnesia:transaction(F),
ejabberd_hooks:run(remove_user, [User, Server]). ejabberd_hooks:run(remove_user, LServer, [User, Server]).
remove_user(User, Server, Password) -> remove_user(User, Server, Password) ->
LUser = jlib:nodeprep(User), LUser = jlib:nodeprep(User),
@ -184,7 +184,7 @@ remove_user(User, Server, Password) ->
end, end,
case mnesia:transaction(F) of case mnesia:transaction(F) of
{atomic, ok} -> {atomic, ok} ->
ejabberd_hooks:run(remove_user, [User, Server]), ejabberd_hooks:run(remove_user, LServer, [User, Server]),
ok; ok;
{atomic, Res} -> {atomic, Res} ->
Res; Res;

View File

@ -170,7 +170,7 @@ is_user_exists(User, _Server) ->
end end
end. end.
remove_user(User, _Server) -> remove_user(User, Server) ->
case jlib:nodeprep(User) of case jlib:nodeprep(User) of
error -> error ->
error; error;
@ -178,10 +178,10 @@ remove_user(User, _Server) ->
Username = ejabberd_odbc:escape(LUser), Username = ejabberd_odbc:escape(LUser),
catch ejabberd_odbc:sql_query( catch ejabberd_odbc:sql_query(
["delete from users where username='", Username ,"'"]), ["delete from users where username='", Username ,"'"]),
ejabberd_hooks:run(remove_user, [User]) ejabberd_hooks:run(remove_user, jlib:nameprep(Server), [User])
end. end.
remove_user(User, _Server, Password) -> remove_user(User, Server, Password) ->
case jlib:nodeprep(User) of case jlib:nodeprep(User) of
error -> error ->
error; error;
@ -196,7 +196,8 @@ remove_user(User, _Server, Password) ->
"where username='", Username, "' and password='", Pass, "';" "where username='", Username, "' and password='", Pass, "';"
"commit"]) of "commit"]) of
{selected, ["password"], [{Password}]} -> {selected, ["password"], [{Password}]} ->
ejabberd_hooks:run(remove_user, [User]), ejabberd_hooks:run(remove_user, jlib:nameprep(Server),
[User]),
ok; ok;
{selected, ["password"], []} -> {selected, ["password"], []} ->
not_exists; not_exists;

View File

@ -340,7 +340,8 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
{auth, _ID, set, {U, P, D, R}} -> {auth, _ID, set, {U, P, D, R}} ->
JID = jlib:make_jid(U, StateData#state.server, R), JID = jlib:make_jid(U, StateData#state.server, R),
case (JID /= error) andalso 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 -> true ->
case ejabberd_auth:check_password( case ejabberd_auth:check_password(
U, StateData#state.server, P, U, StateData#state.server, P,
@ -358,6 +359,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
change_shaper(StateData, JID), change_shaper(StateData, JID),
{Fs, Ts} = ejabberd_hooks:run_fold( {Fs, Ts} = ejabberd_hooks:run_fold(
roster_get_subscription_lists, roster_get_subscription_lists,
StateData#state.server,
{[], []}, {[], []},
[U, StateData#state.server]), [U, StateData#state.server]),
LJID = jlib:jid_tolower( LJID = jlib:jid_tolower(
@ -651,7 +653,8 @@ wait_for_session({xmlstreamelement, El}, StateData) ->
U = StateData#state.user, U = StateData#state.user,
R = StateData#state.resource, R = StateData#state.resource,
JID = StateData#state.jid, 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 -> allow ->
?INFO_MSG("(~w) Opened session for ~s", ?INFO_MSG("(~w) Opened session for ~s",
[StateData#state.socket, [StateData#state.socket,
@ -663,6 +666,7 @@ wait_for_session({xmlstreamelement, El}, StateData) ->
change_shaper(StateData, JID), change_shaper(StateData, JID),
{Fs, Ts} = ejabberd_hooks:run_fold( {Fs, Ts} = ejabberd_hooks:run_fold(
roster_get_subscription_lists, roster_get_subscription_lists,
StateData#state.server,
{[], []}, {[], []},
[U, StateData#state.server]), [U, StateData#state.server]),
LJID = jlib:jid_tolower(jlib:jid_remove_resource(JID)), LJID = jlib:jid_tolower(jlib:jid_remove_resource(JID)),
@ -764,6 +768,7 @@ session_established({xmlstreamelement, El}, StateData) ->
_ -> _ ->
ejabberd_hooks:run( ejabberd_hooks:run(
user_send_packet, user_send_packet,
Server,
[FromJID, ToJID, NewEl]), [FromJID, ToJID, NewEl]),
ejabberd_router:route( ejabberd_router:route(
FromJID, ToJID, NewEl), FromJID, ToJID, NewEl),
@ -772,6 +777,7 @@ session_established({xmlstreamelement, El}, StateData) ->
end; end;
"message" -> "message" ->
ejabberd_hooks:run(user_send_packet, ejabberd_hooks:run(user_send_packet,
Server,
[FromJID, ToJID, NewEl]), [FromJID, ToJID, NewEl]),
ejabberd_router:route(FromJID, ToJID, NewEl), ejabberd_router:route(FromJID, ToJID, NewEl),
StateData; StateData;
@ -983,6 +989,7 @@ handle_info({route, From, To, Packet}, StateName, StateData) ->
Text = xml:element_to_string(FixedPacket), Text = xml:element_to_string(FixedPacket),
send_text(StateData, Text), send_text(StateData, Text),
ejabberd_hooks:run(user_receive_packet, ejabberd_hooks:run(user_receive_packet,
StateData#state.server,
[StateData#state.jid, From, To, FixedPacket]), [StateData#state.jid, From, To, FixedPacket]),
{next_state, StateName, NewState}; {next_state, StateName, NewState};
true -> true ->
@ -1055,7 +1062,8 @@ terminate(_Reason, StateName, StateData) ->
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------
change_shaper(StateData, JID) -> 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). ejabberd_receiver:change_shaper(StateData#state.receiver, Shaper).
send_text(StateData, Text) -> send_text(StateData, Text) ->
@ -1208,6 +1216,7 @@ presence_update(From, Packet, StateData) ->
if if
FromUnavail -> FromUnavail ->
ejabberd_hooks:run(user_available_hook, ejabberd_hooks:run(user_available_hook,
StateData#state.server,
[StateData#state.jid]), [StateData#state.jid]),
resend_offline_messages(StateData), resend_offline_messages(StateData),
presence_broadcast_first( presence_broadcast_first(
@ -1248,21 +1257,25 @@ presence_track(From, To, Packet, StateData) ->
"subscribe" -> "subscribe" ->
ejabberd_router:route(jlib:jid_remove_resource(From), To, Packet), ejabberd_router:route(jlib:jid_remove_resource(From), To, Packet),
ejabberd_hooks:run(roster_out_subscription, ejabberd_hooks:run(roster_out_subscription,
Server,
[User, Server, To, subscribe]), [User, Server, To, subscribe]),
StateData; StateData;
"subscribed" -> "subscribed" ->
ejabberd_router:route(jlib:jid_remove_resource(From), To, Packet), ejabberd_router:route(jlib:jid_remove_resource(From), To, Packet),
ejabberd_hooks:run(roster_out_subscription, ejabberd_hooks:run(roster_out_subscription,
Server,
[User, Server, To, subscribed]), [User, Server, To, subscribed]),
StateData; StateData;
"unsubscribe" -> "unsubscribe" ->
ejabberd_router:route(jlib:jid_remove_resource(From), To, Packet), ejabberd_router:route(jlib:jid_remove_resource(From), To, Packet),
ejabberd_hooks:run(roster_out_subscription, ejabberd_hooks:run(roster_out_subscription,
Server,
[User, Server, To, unsubscribe]), [User, Server, To, unsubscribe]),
StateData; StateData;
"unsubscribed" -> "unsubscribed" ->
ejabberd_router:route(jlib:jid_remove_resource(From), To, Packet), ejabberd_router:route(jlib:jid_remove_resource(From), To, Packet),
ejabberd_hooks:run(roster_out_subscription, ejabberd_hooks:run(roster_out_subscription,
Server,
[User, Server, To, unsubscribed]), [User, Server, To, unsubscribed]),
StateData; StateData;
"error" -> "error" ->
@ -1505,7 +1518,9 @@ process_privacy_iq(From, To,
resend_offline_messages(#state{user = User, resend_offline_messages(#state{user = User,
server = Server, server = Server,
privacy_list = PrivList} = StateData) -> 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 [User, Server]) of
Rs when list(Rs) -> Rs when list(Rs) ->
lists:foreach( lists:foreach(

View File

@ -1,7 +1,7 @@
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------
%%% File : ejabberd_config.erl %%% File : ejabberd_config.erl
%%% Author : Alexey Shchepin <alexey@sevcom.net> %%% Author : Alexey Shchepin <alexey@sevcom.net>
%%% Purpose : %%% Purpose : Load config file
%%% Created : 14 Dec 2002 by Alexey Shchepin <alexey@sevcom.net> %%% Created : 14 Dec 2002 by Alexey Shchepin <alexey@sevcom.net>
%%% Id : $Id$ %%% Id : $Id$
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------
@ -19,12 +19,12 @@
-record(config, {key, value}). -record(config, {key, value}).
-record(local_config, {key, value}). -record(local_config, {key, value}).
-record(state, {opts = [], -record(state, {opts = [],
hosts = [],
override_local = false, override_local = false,
override_global = false, override_global = false,
override_acls = false}). override_acls = false}).
start() -> start() ->
%ets:new(ejabberd_config, [named_table, public]),
mnesia:create_table(config, mnesia:create_table(config,
[{disc_copies, [node()]}, [{disc_copies, [node()]},
{attributes, record_info(fields, config)}]), {attributes, record_info(fields, config)}]),
@ -34,8 +34,6 @@ start() ->
{local_content, true}, {local_content, true},
{attributes, record_info(fields, local_config)}]), {attributes, record_info(fields, local_config)}]),
mnesia:add_table_copy(local_config, node(), ram_copies), 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 Config = case application:get_env(config) of
{ok, Path} -> Path; {ok, Path} -> Path;
undefined -> undefined ->
@ -52,13 +50,38 @@ start() ->
load_file(File) -> load_file(File) ->
case file:consult(File) of case file:consult(File) of
{ok, Terms} -> {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); set_opts(Res);
{error, Reason} -> {error, Reason} ->
?ERROR_MSG("Can't load config file ~p: ~p", [File, Reason]), ?ERROR_MSG("Can't load config file ~p: ~p", [File, Reason]),
exit(file:format_error(Reason)) exit(file:format_error(Reason))
end. 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) -> process_term(Term, State) ->
case Term of case Term of
override_global -> override_global ->
@ -68,20 +91,40 @@ process_term(Term, State) ->
override_acls -> override_acls ->
State#state{override_acls = true}; State#state{override_acls = true};
{acl, ACLName, ACLData} -> {acl, ACLName, ACLData} ->
State#state{opts = process_host_term(Term, global, State);
[acl:to_record(ACLName, ACLData) | State#state.opts]};
{access, RuleName, Rules} -> {access, RuleName, Rules} ->
State#state{opts = [#config{key = {access, RuleName}, 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(Host, ACLName, ACLData) | State#state.opts]};
{access, RuleName, Rules} ->
State#state{opts = [#config{key = {access, RuleName, Host},
value = Rules} | value = Rules} |
State#state.opts]}; State#state.opts]};
{shaper, Name, Data} -> {shaper, Name, Data} ->
State#state{opts = [#config{key = {shaper, Name}, State#state{opts = [#config{key = {shaper, Name, Host},
value = Data} | value = Data} |
State#state.opts]}; State#state.opts]};
{host, Host} -> {host, Host} ->
add_option(hosts, [Host], State); State;
{hosts, Hosts} ->
State;
{Opt, Val} -> {Opt, Val} ->
add_option(Opt, Val, State) add_option({Opt, Host}, Val, State)
end. end.
add_option(Opt, Val, State) -> add_option(Opt, Val, State) ->

View File

@ -16,7 +16,11 @@
add/4, add/4,
delete/4, delete/4,
run/2, run/2,
run_fold/3]). run_fold/3,
add/5,
delete/5,
run/3,
run_fold/4]).
%% gen_server callbacks %% gen_server callbacks
-export([init/1, -export([init/1,
@ -37,13 +41,22 @@ start_link() ->
gen_server:start_link({local, ejabberd_hooks}, ejabberd_hooks, [], []). gen_server:start_link({local, ejabberd_hooks}, ejabberd_hooks, [], []).
add(Hook, Module, Function, Seq) -> 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) -> 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) -> 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}] -> [{_, Ls}] ->
run1(Ls, Hook, Args); run1(Ls, Hook, Args);
[] -> [] ->
@ -51,7 +64,10 @@ run(Hook, Args) ->
end. end.
run_fold(Hook, Val, Args) -> 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}] -> [{_, Ls}] ->
run_fold1(Ls, Hook, Val, Args); run_fold1(Ls, Hook, Val, Args);
[] -> [] ->
@ -82,8 +98,8 @@ init([]) ->
%% {stop, Reason, Reply, State} | (terminate/2 is called) %% {stop, Reason, Reply, State} | (terminate/2 is called)
%% {stop, Reason, State} (terminate/2 is called) %% {stop, Reason, State} (terminate/2 is called)
%%---------------------------------------------------------------------- %%----------------------------------------------------------------------
handle_call({add, Hook, Module, Function, Seq}, From, State) -> handle_call({add, Hook, Host, Module, Function, Seq}, From, State) ->
Reply = case ets:lookup(hooks, Hook) of Reply = case ets:lookup(hooks, {Hook, Host}) of
[{_, Ls}] -> [{_, Ls}] ->
El = {Seq, Module, Function}, El = {Seq, Module, Function},
case lists:member(El, Ls) of case lists:member(El, Ls) of
@ -91,20 +107,20 @@ handle_call({add, Hook, Module, Function, Seq}, From, State) ->
ok; ok;
false -> false ->
NewLs = lists:merge(Ls, [El]), NewLs = lists:merge(Ls, [El]),
ets:insert(hooks, {Hook, NewLs}), ets:insert(hooks, {{Hook, Host}, NewLs}),
ok ok
end; end;
[] -> [] ->
NewLs = [{Seq, Module, Function}], NewLs = [{Seq, Module, Function}],
ets:insert(hooks, {Hook, NewLs}), ets:insert(hooks, {{Hook, Host}, NewLs}),
ok ok
end, end,
{reply, Reply, State}; {reply, Reply, State};
handle_call({delete, Hook, Module, Function, Seq}, From, State) -> handle_call({delete, Hook, Host, Module, Function, Seq}, From, State) ->
Reply = case ets:lookup(hooks, Hook) of Reply = case ets:lookup(hooks, {Hook, Host}) of
[{_, Ls}] -> [{_, Ls}] ->
NewLs = lists:delete({Seq, Module, Function}, Ls), NewLs = lists:delete({Seq, Module, Function}, Ls),
ets:insert(hooks, {Hook, NewLs}), ets:insert(hooks, {{Hook, Host}, NewLs}),
ok; ok;
[] -> [] ->
ok ok

View File

@ -13,9 +13,9 @@
-export([start_link/0, init/0]). -export([start_link/0, init/0]).
-export([route/3, -export([route/3,
register_iq_handler/3,
register_iq_handler/4, register_iq_handler/4,
unregister_iq_handler/1, register_iq_handler/5,
unregister_iq_handler/2,
refresh_iq_handlers/0, refresh_iq_handlers/0,
bounce_resource_packet/3 bounce_resource_packet/3
]). ]).
@ -33,11 +33,11 @@ start_link() ->
init() -> init() ->
lists:foreach( lists:foreach(
fun(Host) -> 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), end, ?MYHOSTS),
catch ets:new(?IQTABLE, [named_table, public]), catch ets:new(?IQTABLE, [named_table, public]),
ejabberd_hooks:add(local_send_to_resource_hook,
?MODULE, bounce_resource_packet, 100),
loop(). loop().
loop() -> loop() ->
@ -51,32 +51,32 @@ loop() ->
ok ok
end, end,
loop(); loop();
{register_iq_handler, XMLNS, Module, Function} -> {register_iq_handler, Host, XMLNS, Module, Function} ->
ets:insert(?IQTABLE, {XMLNS, Module, Function}), ets:insert(?IQTABLE, {{XMLNS, Host}, Module, Function}),
catch mod_disco:register_feature(XMLNS), catch mod_disco:register_feature(Host, XMLNS),
loop(); loop();
{register_iq_handler, XMLNS, Module, Function, Opts} -> {register_iq_handler, Host, XMLNS, Module, Function, Opts} ->
ets:insert(?IQTABLE, {XMLNS, Module, Function, Opts}), ets:insert(?IQTABLE, {{XMLNS, Host}, Module, Function, Opts}),
catch mod_disco:register_feature(XMLNS), catch mod_disco:register_feature(Host, XMLNS),
loop(); loop();
{unregister_iq_handler, XMLNS} -> {unregister_iq_handler, Host, XMLNS} ->
case ets:lookup(?IQTABLE, XMLNS) of case ets:lookup(?IQTABLE, {XMLNS, Host}) of
[{_, Module, Function, Opts}] -> [{_, Module, Function, Opts}] ->
gen_iq_handler:stop_iq_handler(Module, Function, Opts); gen_iq_handler:stop_iq_handler(Module, Function, Opts);
_ -> _ ->
ok ok
end, end,
ets:delete(?IQTABLE, XMLNS), ets:delete(?IQTABLE, {XMLNS, Host}),
catch mod_disco:unregister_feature(XMLNS), catch mod_disco:unregister_feature(Host, XMLNS),
loop(); loop();
refresh_iq_handlers -> refresh_iq_handlers ->
lists:foreach( lists:foreach(
fun(T) -> fun(T) ->
case T of case T of
{XMLNS, _Module, _Function, _Opts} -> {{XMLNS, Host}, _Module, _Function, _Opts} ->
catch mod_disco:register_feature(XMLNS); catch mod_disco:register_feature(Host, XMLNS);
{XMLNS, _Module, _Function} -> {{XMLNS, Host}, _Module, _Function} ->
catch mod_disco:register_feature(XMLNS); catch mod_disco:register_feature(Host, XMLNS);
_ -> _ ->
ok ok
end end
@ -112,6 +112,7 @@ do_route(From, To, Packet) ->
"result" -> ok; "result" -> ok;
_ -> _ ->
ejabberd_hooks:run(local_send_to_resource_hook, ejabberd_hooks:run(local_send_to_resource_hook,
To#jid.lserver,
[From, To, Packet]) [From, To, Packet])
end end
end. end.
@ -120,7 +121,8 @@ process_iq(From, To, Packet) ->
IQ = jlib:iq_query_info(Packet), IQ = jlib:iq_query_info(Packet),
case IQ of case IQ of
#iq{xmlns = XMLNS} -> #iq{xmlns = XMLNS} ->
case ets:lookup(?IQTABLE, XMLNS) of Host = To#jid.lserver,
case ets:lookup(?IQTABLE, {XMLNS, Host}) of
[{_, Module, Function}] -> [{_, Module, Function}] ->
ResIQ = Module:Function(From, To, IQ), ResIQ = Module:Function(From, To, IQ),
if if
@ -131,7 +133,7 @@ process_iq(From, To, Packet) ->
ok ok
end; end;
[{_, Module, Function, Opts}] -> [{_, Module, Function, Opts}] ->
gen_iq_handler:handle(Module, Function, Opts, gen_iq_handler:handle(Host, Module, Function, Opts,
From, To, IQ); From, To, IQ);
[] -> [] ->
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
@ -155,14 +157,14 @@ route(From, To, Packet) ->
ok ok
end. end.
register_iq_handler(XMLNS, Module, Fun) -> register_iq_handler(Host, XMLNS, Module, Fun) ->
ejabberd_local ! {register_iq_handler, XMLNS, Module, Fun}. ejabberd_local ! {register_iq_handler, Host, XMLNS, Module, Fun}.
register_iq_handler(XMLNS, Module, Fun, Opts) -> register_iq_handler(Host, XMLNS, Module, Fun, Opts) ->
ejabberd_local ! {register_iq_handler, XMLNS, Module, Fun, Opts}. ejabberd_local ! {register_iq_handler, Host, XMLNS, Module, Fun, Opts}.
unregister_iq_handler(XMLNS) -> unregister_iq_handler(Host, XMLNS) ->
ejabberd_local ! {unregister_iq_handler, XMLNS}. ejabberd_local ! {unregister_iq_handler, Host, XMLNS}.
refresh_iq_handlers() -> refresh_iq_handlers() ->
ejabberd_local ! refresh_iq_handlers. ejabberd_local ! refresh_iq_handlers.

View File

@ -148,7 +148,7 @@ stream_established({xmlstreamelement, El}, StateData) ->
Key, StateData#state.streamid}), Key, StateData#state.streamid}),
Conns = ?DICT:store({LFrom, LTo}, wait_for_verification, Conns = ?DICT:store({LFrom, LTo}, wait_for_verification,
StateData#state.connections), StateData#state.connections),
change_shaper(StateData, jlib:make_jid("", LFrom, "")), change_shaper(StateData, LTo, jlib:make_jid("", LFrom, "")),
{next_state, {next_state,
stream_established, stream_established,
StateData#state{connections = Conns, StateData#state{connections = Conns,
@ -326,8 +326,8 @@ send_element(Socket, El) ->
send_text(Socket, xml:element_to_string(El)). send_text(Socket, xml:element_to_string(El)).
change_shaper(StateData, JID) -> change_shaper(StateData, Host, JID) ->
Shaper = acl:match_rule(StateData#state.shaper, JID), Shaper = acl:match_rule(Host, StateData#state.shaper, JID),
ejabberd_receiver:change_shaper(StateData#state.receiver, Shaper). ejabberd_receiver:change_shaper(StateData#state.receiver, Shaper).

View File

@ -283,7 +283,7 @@ handle_info({send_element, El}, StateName, StateData) ->
send_element(StateData, El), send_element(StateData, El),
{next_state, StateName, StateData}; {next_state, StateName, StateData};
handle_info({route, From, To, Packet}, 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 -> allow ->
{xmlelement, Name, Attrs, Els} = Packet, {xmlelement, Name, Attrs, Els} = Packet,
Attrs2 = jlib:replace_from_to_attrs(jlib:jid_to_string(From), Attrs2 = jlib:replace_from_to_attrs(jlib:jid_to_string(From),

View File

@ -21,9 +21,9 @@
dirty_get_sessions_list/0, dirty_get_sessions_list/0,
dirty_get_my_sessions_list/0, dirty_get_my_sessions_list/0,
get_vh_session_list/1, get_vh_session_list/1,
register_iq_handler/3,
register_iq_handler/4, register_iq_handler/4,
unregister_iq_handler/1 register_iq_handler/5,
unregister_iq_handler/2
]). ]).
-include("ejabberd.hrl"). -include("ejabberd.hrl").
@ -49,10 +49,13 @@ init() ->
mnesia:add_table_index(presence, us), mnesia:add_table_index(presence, us),
mnesia:subscribe(system), mnesia:subscribe(system),
ets:new(sm_iqtable, [named_table]), ets:new(sm_iqtable, [named_table]),
ejabberd_hooks:add(offline_message_hook, lists:foreach(
fun(Host) ->
ejabberd_hooks:add(offline_message_hook, Host,
ejabberd_sm, bounce_offline_message, 100), ejabberd_sm, bounce_offline_message, 100),
ejabberd_hooks:add(remove_user, ejabberd_hooks:add(remove_user, Host,
ejabberd_sm, disconnect_removed_user, 100), ejabberd_sm, disconnect_removed_user, 100)
end, ?MYHOSTS),
loop(). loop().
loop() -> loop() ->
@ -69,20 +72,20 @@ loop() ->
{mnesia_system_event, {mnesia_down, Node}} -> {mnesia_system_event, {mnesia_down, Node}} ->
clean_table_from_bad_node(Node), clean_table_from_bad_node(Node),
loop(); loop();
{register_iq_handler, XMLNS, Module, Function} -> {register_iq_handler, Host, XMLNS, Module, Function} ->
ets:insert(sm_iqtable, {XMLNS, Module, Function}), ets:insert(sm_iqtable, {{XMLNS, Host}, Module, Function}),
loop(); loop();
{register_iq_handler, XMLNS, Module, Function, Opts} -> {register_iq_handler, Host, XMLNS, Module, Function, Opts} ->
ets:insert(sm_iqtable, {XMLNS, Module, Function, Opts}), ets:insert(sm_iqtable, {{XMLNS, Host}, Module, Function, Opts}),
loop(); loop();
{unregister_iq_handler, XMLNS} -> {unregister_iq_handler, Host, XMLNS} ->
case ets:lookup(sm_iqtable, XMLNS) of case ets:lookup(sm_iqtable, {XMLNS, Host}) of
[{_, Module, Function, Opts}] -> [{_, Module, Function, Opts}] ->
gen_iq_handler:stop_iq_handler(Module, Function, Opts); gen_iq_handler:stop_iq_handler(Module, Function, Opts);
_ -> _ ->
ok ok
end, end,
ets:delete(sm_iqtable, XMLNS), ets:delete(sm_iqtable, {XMLNS, Host}),
loop(); loop();
_ -> _ ->
loop() loop()
@ -170,24 +173,28 @@ do_route(From, To, Packet) ->
"subscribe" -> "subscribe" ->
{ejabberd_hooks:run_fold( {ejabberd_hooks:run_fold(
roster_in_subscription, roster_in_subscription,
LServer,
false, false,
[User, Server, From, subscribe]), [User, Server, From, subscribe]),
true}; true};
"subscribed" -> "subscribed" ->
{ejabberd_hooks:run_fold( {ejabberd_hooks:run_fold(
roster_in_subscription, roster_in_subscription,
LServer,
false, false,
[User, Server, From, subscribed]), [User, Server, From, subscribed]),
true}; true};
"unsubscribe" -> "unsubscribe" ->
{ejabberd_hooks:run_fold( {ejabberd_hooks:run_fold(
roster_in_subscription, roster_in_subscription,
LServer,
false, false,
[User, Server, From, unsubscribe]), [User, Server, From, unsubscribe]),
true}; true};
"unsubscribed" -> "unsubscribed" ->
{ejabberd_hooks:run_fold( {ejabberd_hooks:run_fold(
roster_in_subscription, roster_in_subscription,
LServer,
false, false,
[User, Server, From, unsubscribed]), [User, Server, From, unsubscribed]),
true}; true};
@ -220,6 +227,7 @@ do_route(From, To, Packet) ->
true -> true ->
ejabberd_hooks:run( ejabberd_hooks:run(
offline_subscription_hook, offline_subscription_hook,
LServer,
[From, To, Packet]); [From, To, Packet]);
_ -> _ ->
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
@ -298,6 +306,7 @@ route_message(From, To, Packet) ->
case ejabberd_auth:is_user_exists(LUser, LServer) of case ejabberd_auth:is_user_exists(LUser, LServer) of
true -> true ->
ejabberd_hooks:run(offline_message_hook, ejabberd_hooks:run(offline_message_hook,
LServer,
[From, To, Packet]); [From, To, Packet]);
_ -> _ ->
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
@ -354,7 +363,8 @@ unset_presence(User, Server, Resource, Status) ->
mnesia:delete({presence, USR}) mnesia:delete({presence, USR})
end, end,
mnesia:transaction(F), 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) -> get_user_present_resources(LUser, LServer) ->
US = {LUser, LServer}, US = {LUser, LServer},
@ -392,7 +402,8 @@ process_iq(From, To, Packet) ->
IQ = jlib:iq_query_info(Packet), IQ = jlib:iq_query_info(Packet),
case IQ of case IQ of
#iq{xmlns = XMLNS} -> #iq{xmlns = XMLNS} ->
case ets:lookup(sm_iqtable, XMLNS) of Host = To#jid.lserver,
case ets:lookup(sm_iqtable, {XMLNS, Host}) of
[{_, Module, Function}] -> [{_, Module, Function}] ->
ResIQ = Module:Function(From, To, IQ), ResIQ = Module:Function(From, To, IQ),
if if
@ -403,7 +414,7 @@ process_iq(From, To, Packet) ->
ok ok
end; end;
[{_, Module, Function, Opts}] -> [{_, Module, Function, Opts}] ->
gen_iq_handler:handle(Module, Function, Opts, gen_iq_handler:handle(Host, Module, Function, Opts,
From, To, IQ); From, To, IQ);
[] -> [] ->
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
@ -418,14 +429,14 @@ process_iq(From, To, Packet) ->
ok ok
end. end.
register_iq_handler(XMLNS, Module, Fun) -> register_iq_handler(Host, XMLNS, Module, Fun) ->
ejabberd_sm ! {register_iq_handler, XMLNS, Module, Fun}. ejabberd_sm ! {register_iq_handler, Host, XMLNS, Module, Fun}.
register_iq_handler(XMLNS, Module, Fun, Opts) -> register_iq_handler(Host, XMLNS, Module, Fun, Opts) ->
ejabberd_sm ! {register_iq_handler, XMLNS, Module, Fun, Opts}. ejabberd_sm ! {register_iq_handler, Host, XMLNS, Module, Fun, Opts}.
unregister_iq_handler(XMLNS) -> unregister_iq_handler(Host, XMLNS) ->
ejabberd_sm ! {unregister_iq_handler, XMLNS}. ejabberd_sm ! {unregister_iq_handler, Host, XMLNS}.

View File

@ -11,33 +11,33 @@
-vsn('$Revision$ '). -vsn('$Revision$ ').
-export([start/0, -export([start/0,
start_link/2, start_link/3,
add_iq_handler/5, add_iq_handler/6,
remove_iq_handler/2, remove_iq_handler/3,
stop_iq_handler/3, stop_iq_handler/3,
handle/6, handle/7,
process_iq/5, process_iq/6,
queue_init/2]). queue_init/3]).
-include("ejabberd.hrl"). -include("ejabberd.hrl").
start() -> start() ->
ok. ok.
add_iq_handler(Component, NS, Module, Function, Type) -> add_iq_handler(Component, Host, NS, Module, Function, Type) ->
case Type of case Type of
no_queue -> no_queue ->
Component:register_iq_handler(NS, Module, Function, no_queue); Component:register_iq_handler(Host, NS, Module, Function, no_queue);
one_queue -> one_queue ->
{ok, Pid} = supervisor:start_child(ejabberd_iq_sup, {ok, Pid} = supervisor:start_child(ejabberd_iq_sup,
[Module, Function]), [Host, Module, Function]),
Component:register_iq_handler(NS, Module, Function, Component:register_iq_handler(Host, NS, Module, Function,
{one_queue, Pid}); {one_queue, Pid});
parallel -> parallel ->
Component:register_iq_handler(NS, Module, Function, parallel) Component:register_iq_handler(Host, NS, Module, Function, parallel)
end. end.
remove_iq_handler(Component, NS) -> remove_iq_handler(Component, Host, NS) ->
Component:unregister_iq_handler(NS). Component:unregister_iq_handler(NS).
stop_iq_handler(Module, Function, Opts) -> stop_iq_handler(Module, Function, Opts) ->
@ -48,20 +48,20 @@ stop_iq_handler(Module, Function, Opts) ->
ok ok
end. end.
handle(Module, Function, Opts, From, To, IQ) -> handle(Host, Module, Function, Opts, From, To, IQ) ->
case Opts of case Opts of
no_queue -> no_queue ->
process_iq(Module, Function, From, To, IQ); process_iq(Host, Module, Function, From, To, IQ);
{one_queue, Pid} -> {one_queue, Pid} ->
Pid ! {process_iq, From, To, IQ}; Pid ! {process_iq, From, To, IQ};
parallel -> parallel ->
spawn(?MODULE, process_iq, [Module, Function, From, To, IQ]); spawn(?MODULE, process_iq, [Host, Module, Function, From, To, IQ]);
_ -> _ ->
todo todo
end. end.
process_iq(Module, Function, From, To, IQ) -> process_iq(_Host, Module, Function, From, To, IQ) ->
case catch Module:Function(From, To, IQ) of case catch Module:Function(From, To, IQ) of
{'EXIT', Reason} -> {'EXIT', Reason} ->
?ERROR_MSG("~p", [Reason]); ?ERROR_MSG("~p", [Reason]);
@ -75,18 +75,18 @@ process_iq(Module, Function, From, To, IQ) ->
end end
end. end.
start_link(Module, Function) -> start_link(Host, Module, Function) ->
{ok, proc_lib:spawn_link(?MODULE, queue_init, [Module, Function])}. {ok, proc_lib:spawn_link(?MODULE, queue_init, [Host, Module, Function])}.
queue_init(Module, Function) -> queue_init(Host, Module, Function) ->
queue_loop(Module, Function). queue_loop(Host, Module, Function).
% TODO: use gen_event % TODO: use gen_event
queue_loop(Module, Function) -> queue_loop(Host, Module, Function) ->
receive receive
{process_iq, From, To, IQ} -> {process_iq, From, To, IQ} ->
process_iq(Module, Function, From, To, IQ), process_iq(Host, Module, Function, From, To, IQ),
queue_loop(Module, Function); queue_loop(Host, Module, Function);
_ -> _ ->
queue_loop(Module, Function) queue_loop(Host, Module, Function)
end. end.

View File

@ -11,58 +11,60 @@
-vsn('$Revision$ '). -vsn('$Revision$ ').
-export([start/0, -export([start/0,
start_module/2, start_module/3,
stop_module/1, stop_module/2,
get_opt/2, get_opt/2,
get_opt/3, get_opt/3,
get_module_opt/3, get_module_opt/4,
loaded_modules/0, loaded_modules/1,
loaded_modules_with_opts/0, loaded_modules_with_opts/1,
get_hosts/2]). get_hosts/2,
get_module_proc/2]).
-export([behaviour_info/1]). -export([behaviour_info/1]).
-include("ejabberd.hrl"). -include("ejabberd.hrl").
-record(ejabberd_module, {module, opts}). -record(ejabberd_module, {module_host, opts}).
behaviour_info(callbacks) -> behaviour_info(callbacks) ->
[{start, 1}, [{start, 2},
{stop, 0}]; {stop, 1}];
behaviour_info(_Other) -> behaviour_info(_Other) ->
undefined. undefined.
start() -> start() ->
ets:new(ejabberd_modules, [named_table, ets:new(ejabberd_modules, [named_table,
public, public,
{keypos, #ejabberd_module.module}]), {keypos, #ejabberd_module.module_host}]),
ok. ok.
start_module(Module, Opts) -> start_module(Host, Module, Opts) ->
case catch Module:start(Opts) of case catch Module:start(Host, Opts) of
{'EXIT', Reason} -> {'EXIT', Reason} ->
?ERROR_MSG("~p", [Reason]); ?ERROR_MSG("~p", [Reason]);
_ -> _ ->
ets:insert(ejabberd_modules, #ejabberd_module{module = Module, ets:insert(ejabberd_modules,
#ejabberd_module{module_host = {Module, Host},
opts = Opts}), opts = Opts}),
ok ok
end. end.
stop_module(Module) -> stop_module(Host, Module) ->
case catch Module:stop() of case catch Module:stop(Host) of
{'EXIT', Reason} -> {'EXIT', Reason} ->
?ERROR_MSG("~p", [Reason]); ?ERROR_MSG("~p", [Reason]);
{wait, ProcList} when is_list(ProcList) -> {wait, ProcList} when is_list(ProcList) ->
lists:foreach(fun wait_for_process/1, ProcList), lists:foreach(fun wait_for_process/1, ProcList),
ets:delete(ejabberd_modules, Module), ets:delete(ejabberd_modules, {Module, Host}),
ok; ok;
{wait, Process} -> {wait, Process} ->
wait_for_process(Process), wait_for_process(Process),
ets:delete(ejabberd_modules, Module), ets:delete(ejabberd_modules, {Module, Host}),
ok; ok;
_ -> _ ->
ets:delete(ejabberd_modules, Module), ets:delete(ejabberd_modules, {Module, Host}),
ok ok
end. end.
@ -104,8 +106,8 @@ get_opt(Opt, Opts, Default) ->
Val Val
end. end.
get_module_opt(Module, Opt, Default) -> get_module_opt(Host, Module, Opt, Default) ->
OptsList = ets:lookup(ejabberd_modules, Module), OptsList = ets:lookup(ejabberd_modules, {Module, Host}),
case OptsList of case OptsList of
[] -> [] ->
Default; Default;
@ -113,15 +115,16 @@ get_module_opt(Module, Opt, Default) ->
get_opt(Opt, Opts, Default) get_opt(Opt, Opts, Default)
end. end.
loaded_modules() -> loaded_modules(Host) ->
ets:select(ejabberd_modules, ets:select(ejabberd_modules,
[{#ejabberd_module{_ = '_', module = '$1'}, [{#ejabberd_module{_ = '_', module_host = {'$1', Host}},
[], [],
['$1']}]). ['$1']}]).
loaded_modules_with_opts() -> loaded_modules_with_opts(Host) ->
ets:select(ejabberd_modules, ets:select(ejabberd_modules,
[{#ejabberd_module{_ = '_', module = '$1', opts = '$2'}, [{#ejabberd_module{_ = '_', module_host = {'$1', Host},
opts = '$2'},
[], [],
[{{'$1', '$2'}}]}]). [{{'$1', '$2'}}]}]).
@ -137,3 +140,7 @@ get_hosts(Opts, Prefix) ->
Hosts -> Hosts ->
Hosts Hosts
end. end.
get_module_proc(Host, Base) ->
list_to_atom(atom_to_list(Base) ++ "_" ++ Host).

View File

@ -11,9 +11,9 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/1, -export([start/2,
init/0, init/0,
stop/0, stop/1,
announce/3, announce/3,
send_motd/1]). send_motd/1]).
@ -25,17 +25,18 @@
-define(PROCNAME, ejabberd_announce). -define(PROCNAME, ejabberd_announce).
start(_) -> start(Host, _Opts) ->
mnesia:create_table(motd, [{disc_copies, [node()]}, mnesia:create_table(motd, [{disc_copies, [node()]},
{attributes, record_info(fields, motd)}]), {attributes, record_info(fields, motd)}]),
mnesia:create_table(motd_users, [{disc_copies, [node()]}, mnesia:create_table(motd_users, [{disc_copies, [node()]},
{attributes, record_info(fields, motd_users)}]), {attributes, record_info(fields, motd_users)}]),
update_tables(), update_tables(),
ejabberd_hooks:add(local_send_to_resource_hook, ejabberd_hooks:add(local_send_to_resource_hook, Host,
?MODULE, announce, 50), ?MODULE, announce, 50),
ejabberd_hooks:add(user_available_hook, ejabberd_hooks:add(user_available_hook, Host,
?MODULE, send_motd, 50), ?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() -> init() ->
loop(). loop().
@ -64,36 +65,38 @@ loop() ->
loop() loop()
end. end.
stop() -> stop(Host) ->
ejabberd_hooks:delete(local_send_to_resource_hook, ejabberd_hooks:delete(local_send_to_resource_hook, Host,
?MODULE, announce, 50), ?MODULE, announce, 50),
ejabberd_hooks:delete(sm_register_connection_hook, ejabberd_hooks:delete(sm_register_connection_hook, Host,
?MODULE, send_motd, 50), ?MODULE, send_motd, 50),
exit(whereis(?PROCNAME), stop), Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
{wait, ?PROCNAME}. exit(whereis(Proc), stop),
{wait, Proc}.
announce(From, To, Packet) -> announce(From, To, Packet) ->
case To of case To of
#jid{luser = "", lresource = Res} -> #jid{luser = "", lresource = Res} ->
{xmlelement, Name, _Attrs, _Els} = Packet, {xmlelement, Name, _Attrs, _Els} = Packet,
Proc = gen_mod:get_module_proc(To#jid.lserver, ?PROCNAME),
case {Res, Name} of case {Res, Name} of
{"announce/all", "message"} -> {"announce/all", "message"} ->
?PROCNAME ! {announce_all, From, To, Packet}, Proc ! {announce_all, From, To, Packet},
stop; stop;
{"announce/online", "message"} -> {"announce/online", "message"} ->
?PROCNAME ! {announce_online, From, To, Packet}, Proc ! {announce_online, From, To, Packet},
stop; stop;
{"announce/all-hosts/online", "message"} -> {"announce/all-hosts/online", "message"} ->
?PROCNAME ! {announce_all_hosts_online, From, To, Packet}, Proc ! {announce_all_hosts_online, From, To, Packet},
stop; stop;
{"announce/motd", "message"} -> {"announce/motd", "message"} ->
?PROCNAME ! {announce_motd, From, To, Packet}, Proc ! {announce_motd, From, To, Packet},
stop; stop;
{"announce/motd/update", "message"} -> {"announce/motd/update", "message"} ->
?PROCNAME ! {announce_motd_update, From, To, Packet}, Proc ! {announce_motd_update, From, To, Packet},
stop; stop;
{"announce/motd/delete", "message"} -> {"announce/motd/delete", "message"} ->
?PROCNAME ! {announce_motd_delete, From, To, Packet}, Proc ! {announce_motd_delete, From, To, Packet},
stop; stop;
_ -> _ ->
ok ok
@ -103,8 +106,9 @@ announce(From, To, Packet) ->
end. end.
announce_all(From, To, Packet) -> announce_all(From, To, Packet) ->
Access = gen_mod:get_module_opt(?MODULE, access, none), Host = To#jid.lserver,
case acl:match_rule(Access, From) of Access = gen_mod:get_module_opt(Host, ?MODULE, access, none),
case acl:match_rule(Host, Access, From) of
deny -> deny ->
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED), Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
ejabberd_router:route(To, From, Err); ejabberd_router:route(To, From, Err);
@ -114,24 +118,25 @@ announce_all(From, To, Packet) ->
fun({User, Server}) -> fun({User, Server}) ->
Dest = jlib:make_jid(User, Server, ""), Dest = jlib:make_jid(User, Server, ""),
ejabberd_router:route(Local, Dest, Packet) 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. end.
announce_online(From, To, Packet) -> announce_online(From, To, Packet) ->
Access = gen_mod:get_module_opt(?MODULE, access, none), Host = To#jid.lserver,
case acl:match_rule(Access, From) of Access = gen_mod:get_module_opt(Host, ?MODULE, access, none),
case acl:match_rule(Host, Access, From) of
deny -> deny ->
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED), Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
ejabberd_router:route(To, From, Err); ejabberd_router:route(To, From, Err);
allow -> allow ->
announce_online1(ejabberd_sm:get_vh_session_list(To#jid.lserver), announce_online1(ejabberd_sm:get_vh_session_list(Host),
To#jid.server, To#jid.server,
Packet) Packet)
end. end.
announce_all_hosts_online(From, To, Packet) -> announce_all_hosts_online(From, To, Packet) ->
Access = gen_mod:get_module_opt(?MODULE, access, none), Access = gen_mod:get_module_opt(global, ?MODULE, access, none),
case acl:match_rule(Access, From) of case acl:match_rule(global, Access, From) of
deny -> deny ->
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED), Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
ejabberd_router:route(To, From, Err); ejabberd_router:route(To, From, Err);
@ -150,14 +155,15 @@ announce_online1(Sessions, Server, Packet) ->
end, Sessions). end, Sessions).
announce_motd(From, To, Packet) -> announce_motd(From, To, Packet) ->
Access = gen_mod:get_module_opt(?MODULE, access, none), Host = To#jid.lserver,
case acl:match_rule(Access, From) of Access = gen_mod:get_module_opt(Host, ?MODULE, access, none),
case acl:match_rule(Host, Access, From) of
deny -> deny ->
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED), Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
ejabberd_router:route(To, From, Err); ejabberd_router:route(To, From, Err);
allow -> allow ->
announce_motd_update(To#jid.lserver, Packet), 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), announce_online1(Sessions, To#jid.server, Packet),
F = fun() -> F = fun() ->
lists:foreach( lists:foreach(
@ -169,13 +175,14 @@ announce_motd(From, To, Packet) ->
end. end.
announce_motd_update(From, To, Packet) -> announce_motd_update(From, To, Packet) ->
Access = gen_mod:get_module_opt(?MODULE, access, none), Host = To#jid.lserver,
case acl:match_rule(Access, From) of Access = gen_mod:get_module_opt(Host, ?MODULE, access, none),
case acl:match_rule(Host, Access, From) of
deny -> deny ->
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED), Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
ejabberd_router:route(To, From, Err); ejabberd_router:route(To, From, Err);
allow -> allow ->
announce_motd_update(To#jid.lserver, Packet) announce_motd_update(Host, Packet)
end. end.
announce_motd_update(LServer, Packet) -> announce_motd_update(LServer, Packet) ->
@ -186,13 +193,14 @@ announce_motd_update(LServer, Packet) ->
mnesia:transaction(F). mnesia:transaction(F).
announce_motd_delete(From, To, Packet) -> announce_motd_delete(From, To, Packet) ->
Access = gen_mod:get_module_opt(?MODULE, access, none), Host = To#jid.lserver,
case acl:match_rule(Access, From) of Access = gen_mod:get_module_opt(Host, ?MODULE, access, none),
case acl:match_rule(Host, Access, From) of
deny -> deny ->
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED), Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
ejabberd_router:route(To, From, Err); ejabberd_router:route(To, From, Err);
allow -> allow ->
announce_motd_delete(To#jid.lserver) announce_motd_delete(Host)
end. end.
announce_motd_delete(LServer) -> announce_motd_delete(LServer) ->

View File

@ -12,8 +12,8 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/1, -export([start/2,
stop/0, stop/1,
process_local_iq/3, process_local_iq/3,
process_sm_iq/3]). process_sm_iq/3]).
@ -21,22 +21,22 @@
-include("jlib.hrl"). -include("jlib.hrl").
start(Opts) -> start(Host, Opts) ->
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), 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), ?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), ?MODULE, process_sm_iq, IQDisc),
ok. ok.
stop() -> stop(Host) ->
gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_EJABBERD_CONFIG), gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_EJABBERD_CONFIG),
gen_iq_handler:remove_iq_handler(ejabberd_sm, ?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) -> lang = Lang, sub_el = SubEl} = IQ) ->
case acl:match_rule(configure, From) of case acl:match_rule(To#jid.lserver, configure, From) of
deny -> deny ->
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
allow -> allow ->
@ -719,7 +719,7 @@ search_running_node(SNode, [Node | Nodes]) ->
process_sm_iq(From, To, process_sm_iq(From, To,
#iq{type = Type, xmlns = XMLNS, lang = Lang, sub_el = SubEl} = IQ) -> #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 -> deny ->
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
allow -> allow ->

View File

@ -12,8 +12,8 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/1, -export([start/2,
stop/0, stop/1,
process_local_iq/3]). process_local_iq/3]).
-include("ejabberd.hrl"). -include("ejabberd.hrl").
@ -21,18 +21,18 @@
-define(NS_ECONFIGURE, "http://ejabberd.jabberstudio.org/protocol/configure"). -define(NS_ECONFIGURE, "http://ejabberd.jabberstudio.org/protocol/configure").
start(Opts) -> start(Host, Opts) ->
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), 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), ?MODULE, process_local_iq, IQDisc),
ok. ok.
stop() -> stop(Host) ->
gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_ECONFIGURE). 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) -> process_local_iq(From, To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) ->
case acl:match_rule(configure, From) of case acl:match_rule(To#jid.lserver, configure, From) of
deny -> deny ->
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
allow -> allow ->

View File

@ -12,18 +12,18 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/1, -export([start/2,
stop/0, stop/1,
process_local_iq_items/3, process_local_iq_items/3,
process_local_iq_info/3, process_local_iq_info/3,
process_sm_iq_items/3, process_sm_iq_items/3,
process_sm_iq_info/3, process_sm_iq_info/3,
register_feature/1, register_feature/2,
unregister_feature/1, unregister_feature/2,
register_extra_domain/1, register_extra_domain/1,
unregister_extra_domain/1, unregister_extra_domain/1,
register_sm_feature/1, register_sm_feature/2,
unregister_sm_feature/1, unregister_sm_feature/2,
register_sm_node/4, register_sm_node/4,
unregister_sm_node/1]). unregister_sm_node/1]).
@ -36,23 +36,23 @@
[{"xmlns", ?NS_DISCO_INFO}, [{"xmlns", ?NS_DISCO_INFO},
{"node", SNode}], []}]}). {"node", SNode}], []}]}).
start(Opts) -> start(Host, Opts) ->
ejabberd_local:refresh_iq_handlers(), ejabberd_local:refresh_iq_handlers(),
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), 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), ?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), ?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), ?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), ?MODULE, process_sm_iq_info, IQDisc),
catch ets:new(disco_features, [named_table, ordered_set, public]), catch ets:new(disco_features, [named_table, ordered_set, public]),
register_feature("iq"), register_feature(Host, "iq"),
register_feature("presence"), register_feature(Host, "presence"),
register_feature("presence-invisible"), register_feature(Host, "presence-invisible"),
catch ets:new(disco_extra_domains, [named_table, ordered_set, public]), catch ets:new(disco_extra_domains, [named_table, ordered_set, public]),
ExtraDomains = gen_mod:get_opt(extra_domains, Opts, []), 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]), catch ets:new(disco_sm_nodes, [named_table, ordered_set, public]),
ok. ok.
stop() -> stop(Host) ->
gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_DISCO_ITEMS), gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_ITEMS),
gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_DISCO_INFO), gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO),
gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_DISCO_ITEMS), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_DISCO_ITEMS),
gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_DISCO_INFO), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_DISCO_INFO),
catch ets:delete(disco_features), catch ets:delete(disco_features),
catch ets:delete(disco_extra_domains), catch ets:delete(disco_extra_domains),
ok. ok.
register_feature(Feature) -> register_feature(Host, Feature) ->
catch ets:new(disco_features, [named_table, ordered_set, public]), 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]), 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) -> register_extra_domain(Domain) ->
catch ets:new(disco_extra_domains, [named_table, ordered_set, public]), 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 -> get ->
SNode = xml:get_tag_attr_s("node", SubEl), SNode = xml:get_tag_attr_s("node", SubEl),
Node = string:tokens(SNode, "/"), 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 /= [] -> deny when Node /= [] ->
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
deny -> deny ->
IQ#iq{type = result, IQ#iq{type = result,
sub_el = [{xmlelement, "query", sub_el = [{xmlelement, "query",
[{"xmlns", ?NS_DISCO_ITEMS}], [{"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 jlib:jid_to_string(To), Lang) of
{result, Res} -> {result, Res} ->
IQ#iq{type = result, IQ#iq{type = result,
@ -121,7 +122,7 @@ process_local_iq_items(From, To, #iq{type = Type, lang = Lang, sub_el = SubEl} =
end. 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) -> sub_el = SubEl} = IQ) ->
case Type of case Type of
set -> set ->
@ -129,7 +130,7 @@ process_local_iq_info(From, _To, #iq{type = Type, xmlns = XMLNS,
get -> get ->
SNode = xml:get_tag_attr_s("node", SubEl), SNode = xml:get_tag_attr_s("node", SubEl),
Node = string:tokens(SNode, "/"), 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, Features = lists:map(fun feature_to_xml/1,
ets:tab2list(disco_features)), ets:tab2list(disco_features)),
@ -162,7 +163,7 @@ process_local_iq_info(From, _To, #iq{type = Type, xmlns = XMLNS,
[{"category", "ejabberd"}, [{"category", "ejabberd"},
{"type", "node"}, {"type", "node"},
{"name", ENode}], []}, {"name", ENode}], []},
feature_to_xml({?NS_STATS}) feature_to_xml(?NS_STATS)
] ]
}]}; }]};
{allow, ["running nodes", ENode, "DB"]} -> {allow, ["running nodes", ENode, "DB"]} ->
@ -171,7 +172,7 @@ process_local_iq_info(From, _To, #iq{type = Type, xmlns = XMLNS,
"query", "query",
[{"xmlns", XMLNS}, [{"xmlns", XMLNS},
{"node", SNode}], {"node", SNode}],
[feature_to_xml({?NS_EJABBERD_CONFIG})]}]}; [feature_to_xml(?NS_EJABBERD_CONFIG)]}]};
{allow, ["running nodes", ENode, "modules"]} -> {allow, ["running nodes", ENode, "modules"]} ->
?EMPTY_INFO_RESULT; ?EMPTY_INFO_RESULT;
{allow, ["running nodes", ENode, "modules", _]} -> {allow, ["running nodes", ENode, "modules", _]} ->
@ -179,7 +180,7 @@ process_local_iq_info(From, _To, #iq{type = Type, xmlns = XMLNS,
sub_el = [{xmlelement, "query", sub_el = [{xmlelement, "query",
[{"xmlns", XMLNS}, [{"xmlns", XMLNS},
{"node", SNode}], {"node", SNode}],
[feature_to_xml({?NS_EJABBERD_CONFIG})]}]}; [feature_to_xml(?NS_EJABBERD_CONFIG)]}]};
{allow, ["running nodes", ENode, "backup"]} -> {allow, ["running nodes", ENode, "backup"]} ->
?EMPTY_INFO_RESULT; ?EMPTY_INFO_RESULT;
{allow, ["running nodes", ENode, "backup", _]} -> {allow, ["running nodes", ENode, "backup", _]} ->
@ -187,7 +188,7 @@ process_local_iq_info(From, _To, #iq{type = Type, xmlns = XMLNS,
sub_el = [{xmlelement, "query", sub_el = [{xmlelement, "query",
[{"xmlns", XMLNS}, [{"xmlns", XMLNS},
{"node", SNode}], {"node", SNode}],
[feature_to_xml({?NS_EJABBERD_CONFIG})]}]}; [feature_to_xml(?NS_EJABBERD_CONFIG)]}]};
{allow, ["running nodes", ENode, "import"]} -> {allow, ["running nodes", ENode, "import"]} ->
?EMPTY_INFO_RESULT; ?EMPTY_INFO_RESULT;
{allow, ["running nodes", ENode, "import", _]} -> {allow, ["running nodes", ENode, "import", _]} ->
@ -195,20 +196,22 @@ process_local_iq_info(From, _To, #iq{type = Type, xmlns = XMLNS,
sub_el = [{xmlelement, "query", sub_el = [{xmlelement, "query",
[{"xmlns", XMLNS}, [{"xmlns", XMLNS},
{"node", SNode}], {"node", SNode}],
[feature_to_xml({?NS_EJABBERD_CONFIG})]}]}; [feature_to_xml(?NS_EJABBERD_CONFIG)]}]};
{allow, ["config", _]} -> {allow, ["config", _]} ->
IQ#iq{type = result, IQ#iq{type = result,
sub_el = [{xmlelement, "query", sub_el = [{xmlelement, "query",
[{"xmlns", XMLNS}, [{"xmlns", XMLNS},
{"node", SNode}], {"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]} IQ#iq{type = error, sub_el = [SubEl, ?ERR_ITEM_NOT_FOUND]}
end end
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}], []}. {xmlelement, "feature", [{"var", Feature}], []}.
domain_to_xml({Domain}) -> 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]), 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]), 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) -> register_sm_node(Node, Name, Module, Function) ->
catch ets:new(disco_sm_nodes, [named_table, ordered_set, public]), 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, #jid{luser = LFrom, lserver = LServer} = From,
Self = (LTo == LFrom) andalso (LServer == ?MYNAME), Self = (LTo == LFrom) andalso (LServer == ?MYNAME),
Node = xml:get_tag_attr_s("node", SubEl), 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, _, _} -> {_, set, _, _} ->
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
{_, get, true, []} -> {_, get, true, []} ->
@ -561,7 +564,7 @@ process_sm_iq_info(From, To, #iq{type = Type, xmlns = XMLNS,
#jid{luser = LFrom, lserver = LServer} = From, #jid{luser = LFrom, lserver = LServer} = From,
Self = (LTo == LFrom) andalso (LServer == ?MYNAME), Self = (LTo == LFrom) andalso (LServer == ?MYNAME),
Node = xml:get_tag_attr_s("node", SubEl), 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, _, _} -> {_, set, _, _} ->
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
{allow, get, _, []} -> {allow, get, _, []} ->
@ -569,7 +572,7 @@ process_sm_iq_info(From, To, #iq{type = Type, xmlns = XMLNS,
ets:tab2list(disco_sm_features)), ets:tab2list(disco_sm_features)),
IQ#iq{type = result, IQ#iq{type = result,
sub_el = [{xmlelement, "query", [{"xmlns", XMLNS}], sub_el = [{xmlelement, "query", [{"xmlns", XMLNS}],
[feature_to_xml({?NS_EJABBERD_CONFIG})] ++ [feature_to_xml(?NS_EJABBERD_CONFIG)] ++
Features}]}; Features}]};
{_, get, _, []} -> {_, get, _, []} ->
Features = lists:map(fun feature_to_xml/1, Features = lists:map(fun feature_to_xml/1,

View File

@ -12,17 +12,17 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/1, init/1, stop/0]). -export([start/2, init/1, stop/1]).
-include("ejabberd.hrl"). -include("ejabberd.hrl").
-include("jlib.hrl"). -include("jlib.hrl").
-define(PROCNAME, ejabberd_mod_echo). -define(PROCNAME, ejabberd_mod_echo).
start(Opts) -> start(Host, Opts) ->
%Host = gen_mod:get_opt(host, Opts), MyHost = gen_mod:get_opt(host, Opts, "echo." ++ Host),
Host = gen_mod:get_opt(host, Opts, "echo." ++ ?MYNAME), register(gen_mod:get_module_proc(Host, ?PROCNAME),
register(?PROCNAME, spawn(?MODULE, init, [Host])). spawn(?MODULE, init, [MyHost])).
init(Host) -> init(Host) ->
ejabberd_router:register_route(Host), ejabberd_router:register_route(Host),
@ -40,7 +40,8 @@ loop(Host) ->
loop(Host) loop(Host)
end. end.
stop() -> stop(Host) ->
?PROCNAME ! stop, Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
{wait, ?PROCNAME}. Proc ! stop,
{wait, Proc}.

View File

@ -12,7 +12,7 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/1, init/2, stop/0, -export([start/2, init/2, stop/1,
closed_connection/3, closed_connection/3,
get_user_and_encoding/3]). get_user_and_encoding/3]).
@ -26,44 +26,44 @@
-define(PROCNAME, ejabberd_mod_irc). -define(PROCNAME, ejabberd_mod_irc).
start(Opts) -> start(Host, Opts) ->
iconv:start(), iconv:start(),
mnesia:create_table(irc_custom, mnesia:create_table(irc_custom,
[{disc_copies, [node()]}, [{disc_copies, [node()]},
{attributes, record_info(fields, irc_custom)}]), {attributes, record_info(fields, irc_custom)}]),
Hosts = gen_mod:get_hosts(Opts, "irc."), MyHost = gen_mod:get_opt(host, Opts, "irc." ++ Host),
Host = hd(Hosts), update_table(MyHost),
update_table(Host),
Access = gen_mod:get_opt(access, Opts, all), 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, catch ets:new(irc_connection, [named_table,
public, public,
{keypos, #irc_connection.jid_server_host}]), {keypos, #irc_connection.jid_server_host}]),
ejabberd_router:register_routes(Hosts), ejabberd_router:register_route(Host),
loop(Hosts, Access). loop(Host, Access).
loop(Hosts, Access) -> loop(Host, Access) ->
receive receive
{route, From, To, Packet} -> {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} -> {'EXIT', Reason} ->
?ERROR_MSG("~p", [Reason]); ?ERROR_MSG("~p", [Reason]);
_ -> _ ->
ok ok
end, end,
loop(Hosts, Access); loop(Host, Access);
stop -> stop ->
ejabberd_router:unregister_routes(Hosts), ejabberd_router:unregister_route(Host),
ok; ok;
_ -> _ ->
loop(Hosts, Access) loop(Host, Access)
end. end.
do_route(Host, Access, From, To, Packet) -> do_route(Host, Access, From, To, Packet) ->
case acl:match_rule(Access, From) of case acl:match_rule(Host, Access, From) of
allow -> allow ->
do_route1(Host, From, To, Packet); do_route1(Host, From, To, Packet);
_ -> _ ->
@ -174,9 +174,10 @@ do_route1(Host, From, To, Packet) ->
end. end.
stop() -> stop(Host) ->
?PROCNAME ! stop, Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
{wait, ?PROCNAME}. Proc ! stop,
{wait, Proc}.
closed_connection(Host, From, Server) -> closed_connection(Host, From, Server) ->

View File

@ -12,8 +12,8 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/1, -export([start/2,
stop/0, stop/1,
process_local_iq/3, process_local_iq/3,
process_sm_iq/3, process_sm_iq/3,
on_presence_update/4, on_presence_update/4,
@ -26,28 +26,28 @@
-record(last_activity, {us, timestamp, status}). -record(last_activity, {us, timestamp, status}).
start(Opts) -> start(Host, Opts) ->
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
mnesia:create_table(last_activity, mnesia:create_table(last_activity,
[{disc_copies, [node()]}, [{disc_copies, [node()]},
{attributes, record_info(fields, last_activity)}]), {attributes, record_info(fields, last_activity)}]),
update_table(), 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), ?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), ?MODULE, process_sm_iq, IQDisc),
ejabberd_hooks:add(remove_user, ejabberd_hooks:add(remove_user, Host,
?MODULE, remove_user, 50), ?MODULE, remove_user, 50),
ejabberd_hooks:add(unset_presence_hook, ejabberd_hooks:add(unset_presence_hook, Host,
?MODULE, on_presence_update, 50). ?MODULE, on_presence_update, 50).
stop() -> stop(Host) ->
ejabberd_hooks:delete(remove_user, ejabberd_hooks:delete(remove_user, Host,
?MODULE, remove_user, 50), ?MODULE, remove_user, 50),
ejabberd_hooks:delete(unset_presence_hook, ejabberd_hooks:delete(unset_presence_hook, Host,
?MODULE, on_presence_update, 50), ?MODULE, on_presence_update, 50),
gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_LAST), gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_LAST),
gen_iq_handler:remove_iq_handler(ejabberd_sm, ?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) -> process_local_iq(_From, _To, #iq{type = Type, sub_el = SubEl} = IQ) ->
case Type of case Type of
@ -72,7 +72,8 @@ process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) ->
Server = To#jid.lserver, Server = To#jid.lserver,
{Subscription, _Groups} = {Subscription, _Groups} =
ejabberd_hooks:run_fold( ejabberd_hooks:run_fold(
roster_get_jid_info, {none, []}, [User, Server, From]), roster_get_jid_info, Server,
{none, []}, [User, Server, From]),
if if
(Subscription == both) or (Subscription == from) -> (Subscription == both) or (Subscription == from) ->
case catch mod_privacy:get_user_list(User, Server) of case catch mod_privacy:get_user_list(User, Server) of

View File

@ -12,8 +12,8 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/1, -export([start/2,
stop/0, stop/1,
process_local_iq/3, process_local_iq/3,
process_sm_iq/3, process_sm_iq/3,
on_presence_update/4, on_presence_update/4,
@ -24,24 +24,24 @@
-include("jlib.hrl"). -include("jlib.hrl").
start(Opts) -> start(Host, Opts) ->
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), 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), ?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), ?MODULE, process_sm_iq, IQDisc),
ejabberd_hooks:add(remove_user, ejabberd_hooks:add(remove_user, Host,
?MODULE, remove_user, 50), ?MODULE, remove_user, 50),
ejabberd_hooks:add(unset_presence_hook, ejabberd_hooks:add(unset_presence_hook, Host,
?MODULE, on_presence_update, 50). ?MODULE, on_presence_update, 50).
stop() -> stop(Host) ->
ejabberd_hooks:delete(remove_user, ejabberd_hooks:delete(remove_user, Host,
?MODULE, remove_user, 50), ?MODULE, remove_user, 50),
ejabberd_hooks:delete(unset_presence_hook, ejabberd_hooks:delete(unset_presence_hook, Host,
?MODULE, on_presence_update, 50), ?MODULE, on_presence_update, 50),
gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_LAST), gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_LAST),
gen_iq_handler:remove_iq_handler(ejabberd_sm, ?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) -> process_local_iq(_From, _To, #iq{type = Type, sub_el = SubEl} = IQ) ->
case Type of case Type of
@ -66,7 +66,8 @@ process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) ->
Server = To#jid.lserver, Server = To#jid.lserver,
{Subscription, _Groups} = {Subscription, _Groups} =
ejabberd_hooks:run_fold( ejabberd_hooks:run_fold(
roster_get_jid_info, {none, []}, [User, From]), roster_get_jid_info, Server,
{none, []}, [User, From]),
if if
(Subscription == both) or (Subscription == from) -> (Subscription == both) or (Subscription == from) ->
case catch mod_privacy:get_user_list(User, Server) of case catch mod_privacy:get_user_list(User, Server) of

View File

@ -12,10 +12,10 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/1, -export([start/2,
init/2, init/3,
stop/0, stop/1,
room_destroyed/2, room_destroyed/3,
store_room/3, store_room/3,
restore_room/2, restore_room/2,
forget_room/2, forget_room/2,
@ -32,60 +32,59 @@
-define(PROCNAME, ejabberd_mod_muc). -define(PROCNAME, ejabberd_mod_muc).
start(Opts) -> start(Host, Opts) ->
mnesia:create_table(muc_room, mnesia:create_table(muc_room,
[{disc_copies, [node()]}, [{disc_copies, [node()]},
{attributes, record_info(fields, muc_room)}]), {attributes, record_info(fields, muc_room)}]),
mnesia:create_table(muc_registered, mnesia:create_table(muc_registered,
[{disc_copies, [node()]}, [{disc_copies, [node()]},
{attributes, record_info(fields, muc_registered)}]), {attributes, record_info(fields, muc_registered)}]),
Hosts = gen_mod:get_hosts(Opts, "conference."), MyHost = gen_mod:get_opt(host, Opts, "conference." ++ Host),
Host = hd(Hosts), update_tables(MyHost),
update_tables(Host),
mnesia:add_table_index(muc_registered, nick), mnesia:add_table_index(muc_registered, nick),
Access = gen_mod:get_opt(access, Opts, all), Access = gen_mod:get_opt(access, Opts, all),
AccessCreate = gen_mod:get_opt(access_create, Opts, all), AccessCreate = gen_mod:get_opt(access_create, Opts, all),
AccessAdmin = gen_mod:get_opt(access_admin, Opts, none), AccessAdmin = gen_mod:get_opt(access_admin, Opts, none),
register(?PROCNAME, register(gen_mod:get_module_proc(Host, ?PROCNAME),
spawn(?MODULE, init, 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, catch ets:new(muc_online_room, [named_table,
public, public,
{keypos, #muc_online_room.name_host}]), {keypos, #muc_online_room.name_host}]),
ejabberd_router:register_routes(Hosts), ejabberd_router:register_route(Host),
load_permanent_rooms(Access), load_permanent_rooms(Host, ServerHost, Access),
loop(Hosts, Access). loop(Host, ServerHost, Access).
loop(Hosts, Access) -> loop(Host, ServerHost, Access) ->
receive receive
{route, From, To, Packet} -> {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} -> {'EXIT', Reason} ->
?ERROR_MSG("~p", [Reason]); ?ERROR_MSG("~p", [Reason]);
_ -> _ ->
ok ok
end, end,
loop(Hosts, Access); loop(Host, ServerHost, Access);
{room_destroyed, RoomHost} -> {room_destroyed, RoomHost} ->
ets:delete(muc_online_room, RoomHost), ets:delete(muc_online_room, RoomHost),
loop(Hosts, Access); loop(Host, ServerHost, Access);
stop -> stop ->
ejabberd_router:unregister_routes(Hosts), ejabberd_router:unregister_route(Host),
ok; ok;
_ -> _ ->
loop(Hosts, Access) loop(Host, ServerHost, Access)
end. end.
do_route(Host, Access, From, To, Packet) -> do_route(Host, ServerHost, Access, From, To, Packet) ->
{AccessRoute, _AccessCreate, _AccessAdmin} = Access, {AccessRoute, _AccessCreate, _AccessAdmin} = Access,
case acl:match_rule(AccessRoute, From) of case acl:match_rule(ServerHost, AccessRoute, From) of
allow -> allow ->
do_route1(Host, Access, From, To, Packet); do_route1(Host, ServerHost, Access, From, To, Packet);
_ -> _ ->
{xmlelement, _Name, Attrs, _Els} = Packet, {xmlelement, _Name, Attrs, _Els} = Packet,
Lang = xml:get_attr_s("xml:lang", Attrs), Lang = xml:get_attr_s("xml:lang", Attrs),
@ -96,7 +95,7 @@ do_route(Host, Access, From, To, Packet) ->
end. end.
do_route1(Host, Access, From, To, Packet) -> do_route1(Host, ServerHost, Access, From, To, Packet) ->
{_AccessRoute, AccessCreate, AccessAdmin} = Access, {_AccessRoute, AccessCreate, AccessAdmin} = Access,
{Room, _, Nick} = jlib:jid_tolower(To), {Room, _, Nick} = jlib:jid_tolower(To),
{xmlelement, Name, Attrs, _Els} = Packet, {xmlelement, Name, Attrs, _Els} = Packet,
@ -178,7 +177,7 @@ do_route1(Host, Access, From, To, Packet) ->
"error" -> "error" ->
ok; ok;
_ -> _ ->
case acl:match_rule(AccessAdmin, From) of case acl:match_rule(ServerHost, AccessAdmin, From) of
allow -> allow ->
Msg = xml:get_path_s( Msg = xml:get_path_s(
Packet, Packet,
@ -216,11 +215,12 @@ do_route1(Host, Access, From, To, Packet) ->
Type = xml:get_attr_s("type", Attrs), Type = xml:get_attr_s("type", Attrs),
case {Name, Type} of case {Name, Type} of
{"presence", ""} -> {"presence", ""} ->
case acl:match_rule(AccessCreate, From) of case acl:match_rule(ServerHost, AccessCreate, From) of
allow -> allow ->
?DEBUG("MUC: open new room '~s'~n", [Room]), ?DEBUG("MUC: open new room '~s'~n", [Room]),
{ok, Pid} = mod_muc_room:start( {ok, Pid} = mod_muc_room:start(
Host, Access, Room, From, Nick), Host, ServerHost, Access,
Room, From, Nick),
ets:insert( ets:insert(
muc_online_room, muc_online_room,
#muc_online_room{name_host = {Room, Host}, #muc_online_room{name_host = {Room, Host},
@ -252,13 +252,15 @@ do_route1(Host, Access, From, To, Packet) ->
room_destroyed(Host, Room) -> room_destroyed(Host, Room, ServerHost) ->
?PROCNAME ! {room_destroyed, {Room, Host}}, gen_mod:get_module_proc(ServerHost, ?PROCNAME) !
{room_destroyed, {Room, Host}},
ok. ok.
stop() -> stop(Host) ->
?PROCNAME ! stop, Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
{wait, ?PROCNAME}. Proc ! stop,
{wait, Proc}.
store_room(Host, Name, Opts) -> store_room(Host, Name, Opts) ->
@ -284,8 +286,11 @@ forget_room(Host, Name) ->
mnesia:transaction(F). mnesia:transaction(F).
load_permanent_rooms(Access) -> load_permanent_rooms(Host, ServerHost, Access) ->
case catch mnesia:dirty_select(muc_room, [{'_', [], ['$_']}]) of case catch mnesia:dirty_select(
muc_room, [{#muc_room{name_host = {'_', Host}, _ = '_'},
[],
['$_']}]) of
{'EXIT', Reason} -> {'EXIT', Reason} ->
?ERROR_MSG("~p", [Reason]), ?ERROR_MSG("~p", [Reason]),
ok; ok;
@ -294,6 +299,7 @@ load_permanent_rooms(Access) ->
{Room, Host} = R#muc_room.name_host, {Room, Host} = R#muc_room.name_host,
{ok, Pid} = mod_muc_room:start( {ok, Pid} = mod_muc_room:start(
Host, Host,
ServerHost,
Access, Access,
Room, Room,
R#muc_room.opts), R#muc_room.opts),

View File

@ -14,8 +14,8 @@
%% External exports %% External exports
-export([start/5, -export([start/6,
start/4, start/5,
route/4]). route/4]).
%% gen_fsm callbacks %% gen_fsm callbacks
@ -59,6 +59,7 @@
-record(state, {room, -record(state, {room,
host, host,
server_host,
access, access,
jid, jid,
config = #config{}, config = #config{},
@ -82,11 +83,12 @@
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------
%%% API %%% API
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------
start(Host, Access, Room, Creator, Nick) -> start(Host, ServerHost, Access, Room, Creator, Nick) ->
gen_fsm:start(?MODULE, [Host, Access, Room, Creator, Nick], ?FSMOPTS). gen_fsm:start(?MODULE, [Host, ServerHost, Access, Room, Creator, Nick],
?FSMOPTS).
start(Host, Access, Room, Opts) -> start(Host, ServerHost, Access, Room, Opts) ->
gen_fsm:start(?MODULE, [Host, Access, Room, Opts], ?FSMOPTS). gen_fsm:start(?MODULE, [Host, ServerHost, Access, Room, Opts], ?FSMOPTS).
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------
%%% Callback functions from gen_fsm %%% Callback functions from gen_fsm
@ -99,16 +101,18 @@ start(Host, Access, Room, Opts) ->
%% ignore | %% ignore |
%% {stop, StopReason} %% {stop, StopReason}
%%---------------------------------------------------------------------- %%----------------------------------------------------------------------
init([Host, Access, Room, Creator, Nick]) -> init([Host, ServerHost, Access, Room, Creator, Nick]) ->
State = set_affiliation(Creator, owner, State = set_affiliation(Creator, owner,
#state{host = Host, #state{host = Host,
server_host = ServerHost,
access = Access, access = Access,
room = Room, room = Room,
jid = jlib:make_jid(Room, Host, ""), jid = jlib:make_jid(Room, Host, ""),
just_created = true}), just_created = true}),
{ok, normal_state, State}; {ok, normal_state, State};
init([Host, Access, Room, Opts]) -> init([Host, ServerHost, Access, Room, Opts]) ->
State = set_opts(Opts, #state{host = Host, State = set_opts(Opts, #state{host = Host,
server_host = ServerHost,
access = Access, access = Access,
room = Room, room = Room,
jid = jlib:make_jid(Room, Host, "")}), jid = jlib:make_jid(Room, Host, "")}),
@ -652,7 +656,8 @@ handle_info(_Info, StateName, StateData) ->
%% Returns: any %% Returns: any
%%---------------------------------------------------------------------- %%----------------------------------------------------------------------
terminate(_Reason, _StateName, StateData) -> 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. ok.
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------
@ -732,7 +737,7 @@ set_affiliation_and_reason(JID, Affiliation, Reason, StateData) ->
get_affiliation(JID, StateData) -> get_affiliation(JID, StateData) ->
{_AccessRoute, _AccessCreate, AccessAdmin} = StateData#state.access, {_AccessRoute, _AccessCreate, AccessAdmin} = StateData#state.access,
Res = Res =
case acl:match_rule(AccessAdmin, JID) of case acl:match_rule(StateData#state.server_host, AccessAdmin, JID) of
allow -> allow ->
owner; owner;
_ -> _ ->

View File

@ -11,9 +11,9 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/1, -export([start/2,
init/0, init/0,
stop/0, stop/1,
store_packet/3, store_packet/3,
resend_offline_messages/2, resend_offline_messages/2,
pop_offline_messages/3, pop_offline_messages/3,
@ -29,21 +29,22 @@
-define(PROCNAME, ejabberd_offline). -define(PROCNAME, ejabberd_offline).
-define(OFFLINE_TABLE_LOCK_THRESHOLD, 1000). -define(OFFLINE_TABLE_LOCK_THRESHOLD, 1000).
start(_) -> start(Host, _Opts) ->
mnesia:create_table(offline_msg, mnesia:create_table(offline_msg,
[{disc_only_copies, [node()]}, [{disc_only_copies, [node()]},
{type, bag}, {type, bag},
{attributes, record_info(fields, offline_msg)}]), {attributes, record_info(fields, offline_msg)}]),
update_table(), update_table(),
ejabberd_hooks:add(offline_message_hook, ejabberd_hooks:add(offline_message_hook, Host,
?MODULE, store_packet, 50), ?MODULE, store_packet, 50),
ejabberd_hooks:add(offline_subscription_hook, ejabberd_hooks:add(offline_subscription_hook, Host,
?MODULE, store_packet, 50), ?MODULE, store_packet, 50),
ejabberd_hooks:add(resend_offline_messages_hook, ejabberd_hooks:add(resend_offline_messages_hook, Host,
?MODULE, pop_offline_messages, 50), ?MODULE, pop_offline_messages, 50),
ejabberd_hooks:add(remove_user, ejabberd_hooks:add(remove_user, Host,
?MODULE, remove_user, 50), ?MODULE, remove_user, 50),
register(?PROCNAME, spawn(?MODULE, init, [])). register(gen_mod:get_module_proc(Host, ?PROCNAME),
spawn(?MODULE, init, [])).
init() -> init() ->
loop(). loop().
@ -79,17 +80,18 @@ receive_all(Msgs) ->
end. end.
stop() -> stop(Host) ->
ejabberd_hooks:delete(offline_message_hook, ejabberd_hooks:delete(offline_message_hook, Host,
?MODULE, store_packet, 50), ?MODULE, store_packet, 50),
ejabberd_hooks:delete(offline_subscription_hook, ejabberd_hooks:delete(offline_subscription_hook, Host,
?MODULE, store_packet, 50), ?MODULE, store_packet, 50),
ejabberd_hooks:delete(resend_offline_messages_hook, ejabberd_hooks:delete(resend_offline_messages_hook, Host,
?MODULE, pop_offline_messages, 50), ?MODULE, pop_offline_messages, 50),
ejabberd_hooks:delete(remove_user, ejabberd_hooks:delete(remove_user, Host,
?MODULE, remove_user, 50), ?MODULE, remove_user, 50),
exit(whereis(?PROCNAME), stop), Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
{wait, ?PROCNAME}. exit(whereis(Proc), stop),
{wait, Proc}.
store_packet(From, To, Packet) -> store_packet(From, To, Packet) ->
Type = xml:get_tag_attr_s("type", Packet), Type = xml:get_tag_attr_s("type", Packet),

View File

@ -11,9 +11,9 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/1, -export([start/2,
init/0, init/0,
stop/0, stop/1,
store_packet/3, store_packet/3,
pop_offline_messages/2, pop_offline_messages/2,
remove_user/1]). remove_user/1]).
@ -26,16 +26,16 @@
-define(PROCNAME, ejabberd_offline). -define(PROCNAME, ejabberd_offline).
-define(OFFLINE_TABLE_LOCK_THRESHOLD, 1000). -define(OFFLINE_TABLE_LOCK_THRESHOLD, 1000).
start(_) -> start(Host, _Opts) ->
% TODO: remove % TODO: remove
ejabberd_odbc:start(), ejabberd_odbc:start(),
ejabberd_hooks:add(offline_message_hook, ejabberd_hooks:add(offline_message_hook, Host,
?MODULE, store_packet, 50), ?MODULE, store_packet, 50),
ejabberd_hooks:add(offline_subscription_hook, ejabberd_hooks:add(offline_subscription_hook, Host,
?MODULE, store_packet, 50), ?MODULE, store_packet, 50),
ejabberd_hooks:add(resend_offline_messages_hook, ejabberd_hooks:add(resend_offline_messages_hook, Host,
?MODULE, pop_offline_messages, 50), ?MODULE, pop_offline_messages, 50),
ejabberd_hooks:add(remove_user, ejabberd_hooks:add(remove_user, Host,
?MODULE, remove_user, 50), ?MODULE, remove_user, 50),
register(?PROCNAME, spawn(?MODULE, init, [])). register(?PROCNAME, spawn(?MODULE, init, [])).
@ -95,14 +95,14 @@ receive_all(Msgs) ->
end. end.
stop() -> stop(Host) ->
ejabberd_hooks:delete(offline_message_hook, ejabberd_hooks:delete(offline_message_hook, Host,
?MODULE, store_packet, 50), ?MODULE, store_packet, 50),
ejabberd_hooks:delete(offline_subscription_hook, ejabberd_hooks:delete(offline_subscription_hook, Host,
?MODULE, store_packet, 50), ?MODULE, store_packet, 50),
ejabberd_hooks:delete(resend_offline_messages_hook, ejabberd_hooks:delete(resend_offline_messages_hook, Host,
?MODULE, pop_offline_messages, 50), ?MODULE, pop_offline_messages, 50),
ejabberd_hooks:delete(remove_user, ejabberd_hooks:delete(remove_user, Host,
?MODULE, remove_user, 50), ?MODULE, remove_user, 50),
exit(whereis(?PROCNAME), stop), exit(whereis(?PROCNAME), stop),
ok. ok.

View File

@ -12,7 +12,7 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/1, stop/0, -export([start/2, stop/1,
process_iq/3, process_iq/3,
process_iq_set/3, process_iq_set/3,
process_iq_get/4, process_iq_get/4,
@ -42,16 +42,16 @@
-record(userlist, {name = none, list = []}). -record(userlist, {name = none, list = []}).
start(Opts) -> start(Host, Opts) ->
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
mnesia:create_table(privacy, [{disc_copies, [node()]}, mnesia:create_table(privacy, [{disc_copies, [node()]},
{attributes, record_info(fields, privacy)}]), {attributes, record_info(fields, privacy)}]),
update_table(), 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). ?MODULE, process_iq, IQDisc).
stop() -> stop(Host) ->
gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_PRIVACY). gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_PRIVACY).
process_iq(From, _To, IQ) -> process_iq(From, _To, IQ) ->
#iq{type = Type, sub_el = SubEl} = IQ, #iq{type = Type, sub_el = SubEl} = IQ,
@ -555,32 +555,32 @@ check_packet(User, Server,
LJID = jlib:jid_tolower(From), LJID = jlib:jid_tolower(From),
{Subscription, Groups} = {Subscription, Groups} =
ejabberd_hooks:run_fold( ejabberd_hooks:run_fold(
roster_get_jid_info, {none, []}, roster_get_jid_info, jlib:nameprep(Server),
[User, Server, LJID]), {none, []}, [User, Server, LJID]),
check_packet_aux(List, message, check_packet_aux(List, message,
LJID, Subscription, Groups); LJID, Subscription, Groups);
{iq, in} -> {iq, in} ->
LJID = jlib:jid_tolower(From), LJID = jlib:jid_tolower(From),
{Subscription, Groups} = {Subscription, Groups} =
ejabberd_hooks:run_fold( ejabberd_hooks:run_fold(
roster_get_jid_info, {none, []}, roster_get_jid_info, jlib:nameprep(Server),
[User, Server, LJID]), {none, []}, [User, Server, LJID]),
check_packet_aux(List, iq, check_packet_aux(List, iq,
LJID, Subscription, Groups); LJID, Subscription, Groups);
{presence, in} -> {presence, in} ->
LJID = jlib:jid_tolower(From), LJID = jlib:jid_tolower(From),
{Subscription, Groups} = {Subscription, Groups} =
ejabberd_hooks:run_fold( ejabberd_hooks:run_fold(
roster_get_jid_info, {none, []}, roster_get_jid_info, jlib:nameprep(Server),
[User, Server, LJID]), {none, []}, [User, Server, LJID]),
check_packet_aux(List, presence_in, check_packet_aux(List, presence_in,
LJID, Subscription, Groups); LJID, Subscription, Groups);
{presence, out} -> {presence, out} ->
LJID = jlib:jid_tolower(To), LJID = jlib:jid_tolower(To),
{Subscription, Groups} = {Subscription, Groups} =
ejabberd_hooks:run_fold( ejabberd_hooks:run_fold(
roster_get_jid_info, {none, []}, roster_get_jid_info, jlib:nameprep(Server),
[User, Server, LJID]), {none, []}, [User, Server, LJID]),
check_packet_aux(List, presence_out, check_packet_aux(List, presence_out,
LJID, Subscription, Groups); LJID, Subscription, Groups);
_ -> _ ->
@ -592,12 +592,12 @@ check_packet_aux([], _PType, _JID, _Subscription, _Groups) ->
allow; allow;
check_packet_aux([Item | List], PType, JID, Subscription, Groups) -> check_packet_aux([Item | List], PType, JID, Subscription, Groups) ->
#listitem{type = Type, value = Value, action = Action} = Item, #listitem{type = Type, value = Value, action = Action} = Item,
case is_ptype_match(Item, PType) of
true ->
case Type of case Type of
none -> none ->
Action; Action;
_ -> _ ->
case is_ptype_match(Item, PType) of
true ->
case is_type_match(Type, Value, case is_type_match(Type, Value,
JID, Subscription, Groups) of JID, Subscription, Groups) of
true -> true ->
@ -605,10 +605,10 @@ check_packet_aux([Item | List], PType, JID, Subscription, Groups) ->
false -> false ->
check_packet_aux(List, PType, check_packet_aux(List, PType,
JID, Subscription, Groups) JID, Subscription, Groups)
end
end; end;
false -> false ->
check_packet_aux(List, PType, JID, Subscription, Groups) check_packet_aux(List, PType, JID, Subscription, Groups)
end
end. end.

View File

@ -12,8 +12,8 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/1, -export([start/2,
stop/0, stop/1,
process_sm_iq/3, process_sm_iq/3,
remove_user/2]). remove_user/2]).
@ -22,21 +22,21 @@
-record(private_storage, {usns, xml}). -record(private_storage, {usns, xml}).
start(Opts) -> start(Host, Opts) ->
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
mnesia:create_table(private_storage, mnesia:create_table(private_storage,
[{disc_only_copies, [node()]}, [{disc_only_copies, [node()]},
{attributes, record_info(fields, private_storage)}]), {attributes, record_info(fields, private_storage)}]),
update_table(), update_table(),
ejabberd_hooks:add(remove_user, ejabberd_hooks:add(remove_user, Host,
?MODULE, remove_user, 50), ?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). ?MODULE, process_sm_iq, IQDisc).
stop() -> stop(Host) ->
ejabberd_hooks:delete(remove_user, ejabberd_hooks:delete(remove_user, Host,
?MODULE, remove_user, 50), ?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) -> process_sm_iq(From, _To, #iq{type = Type, sub_el = SubEl} = IQ) ->

View File

@ -12,10 +12,10 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/1, -export([start/2,
init/3, init/4,
loop/2, loop/2,
stop/0, stop/1,
system_continue/3, system_continue/3,
system_terminate/4, system_terminate/4,
system_code_change/4]). system_code_change/4]).
@ -37,37 +37,34 @@
-define(PROCNAME, ejabberd_mod_pubsub). -define(PROCNAME, ejabberd_mod_pubsub).
start(Opts) -> start(Host, Opts) ->
mnesia:create_table(pubsub_node, mnesia:create_table(pubsub_node,
[{disc_only_copies, [node()]}, [{disc_only_copies, [node()]},
{attributes, record_info(fields, pubsub_node)}]), {attributes, record_info(fields, pubsub_node)}]),
Hosts = gen_mod:get_hosts(Opts, "pubsub."), MyHost = gen_mod:get_opt(host, Opts, "pubsub." ++ Host),
Host = hd(Hosts), update_table(MyHost),
update_table(Host),
mnesia:add_table_index(pubsub_node, host_parent), mnesia:add_table_index(pubsub_node, host_parent),
ServedHosts = gen_mod:get_opt(served_hosts, Opts, []), ServedHosts = gen_mod:get_opt(served_hosts, Opts, []),
register(?PROCNAME, register(gen_mod:get_module_proc(Host, ?PROCNAME),
proc_lib:spawn_link(?MODULE, init, [Hosts, ServedHosts, self()])). proc_lib:spawn_link(?MODULE, init,
[MyHost, Host, ServedHosts, self()])).
-define(MYJID, #jid{user = "", server = Host, resource = "", -define(MYJID, #jid{user = "", server = Host, resource = "",
luser = "", lserver = Host, lresource = ""}). luser = "", lserver = Host, lresource = ""}).
init(Hosts, ServedHosts, Parent) -> init(Host, ServerHost, ServedHosts, Parent) ->
ejabberd_router:register_routes(Hosts), ejabberd_router:register_route(Host),
lists:foreach(
fun(Host) ->
create_new_node(Host, ["pubsub"], ?MYJID), create_new_node(Host, ["pubsub"], ?MYJID),
create_new_node(Host, ["pubsub", "nodes"], ?MYJID), create_new_node(Host, ["pubsub", "nodes"], ?MYJID),
create_new_node(Host, ["home"], ?MYJID), create_new_node(Host, ["home"], ?MYJID),
create_new_node(Host, ["home", find_my_host(Host)], ?MYJID), create_new_node(Host, ["home", ServerHost], ?MYJID),
lists:foreach(fun(H) -> lists:foreach(fun(H) ->
create_new_node(Host, ["home", H], ?MYJID) create_new_node(Host, ["home", H], ?MYJID)
end, ServedHosts) end, ServedHosts),
end, Hosts), loop(Host, Parent).
loop(Hosts, Parent).
loop(Hosts, Parent) -> loop(Host, Parent) ->
receive receive
{route, From, To, Packet} -> {route, From, To, Packet} ->
case catch do_route(To#jid.lserver, From, To, Packet) of case catch do_route(To#jid.lserver, From, To, Packet) of
@ -76,19 +73,19 @@ loop(Hosts, Parent) ->
_ -> _ ->
ok ok
end, end,
loop(Hosts, Parent); loop(Host, Parent);
{room_destroyed, Room} -> {room_destroyed, Room} ->
ets:delete(muc_online_room, Room), ets:delete(muc_online_room, Room),
loop(Hosts, Parent); loop(Host, Parent);
stop -> stop ->
ejabberd_router:unregister_routes(Hosts), ejabberd_router:unregister_route(Host),
ok; ok;
reload -> reload ->
?MODULE:loop(Hosts, Parent); ?MODULE:loop(Host, Parent);
{system, From, Request} -> {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. end.
@ -202,9 +199,10 @@ do_route(Host, From, To, Packet) ->
stop() -> stop(Host) ->
?PROCNAME ! stop, Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
{wait, ?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) -> update_table(Host) ->
Fields = record_info(fields, pubsub_node), Fields = record_info(fields, pubsub_node),

View File

@ -1,7 +1,7 @@
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------
%%% File : mod_register.erl %%% File : mod_register.erl
%%% Author : Alexey Shchepin <alexey@sevcom.net> %%% Author : Alexey Shchepin <alexey@sevcom.net>
%%% Purpose : %%% Purpose : Inband registration support
%%% Created : 8 Dec 2002 by Alexey Shchepin <alexey@sevcom.net> %%% Created : 8 Dec 2002 by Alexey Shchepin <alexey@sevcom.net>
%%% Id : $Id$ %%% Id : $Id$
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------
@ -12,24 +12,27 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/1, stop/0, process_iq/3]). -export([start/2,
stop/1,
process_iq/3]).
-include("ejabberd.hrl"). -include("ejabberd.hrl").
-include("jlib.hrl"). -include("jlib.hrl").
start(Opts) -> start(Host, Opts) ->
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), 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), ?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), ?MODULE, process_iq, IQDisc),
ok. ok.
stop() -> stop(Host) ->
gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_REGISTER), gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_REGISTER),
gen_iq_handler:remove_iq_handler(ejabberd_sm, ?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 case Type of
set -> set ->
UTag = xml:get_subtag(SubEl, "username"), UTag = xml:get_subtag(SubEl, "username"),
@ -123,8 +126,8 @@ try_register(User, Server, Password) ->
{error, ?ERR_BAD_REQUEST}; {error, ?ERR_BAD_REQUEST};
_ -> _ ->
JID = jlib:make_jid(User, Server, ""), JID = jlib:make_jid(User, Server, ""),
Access = gen_mod:get_module_opt(?MODULE, access, all), Access = gen_mod:get_module_opt(Server, ?MODULE, access, all),
case acl:match_rule(Access, JID) of case acl:match_rule(Server, Access, JID) of
deny -> deny ->
{error, ?ERR_CONFLICT}; {error, ?ERR_CONFLICT};
allow -> allow ->

View File

@ -12,7 +12,7 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/1, stop/0, -export([start/2, stop/1,
process_iq/3, process_iq/3,
process_local_iq/3, process_local_iq/3,
get_user_roster/2, get_user_roster/2,
@ -28,41 +28,41 @@
-include("mod_roster.hrl"). -include("mod_roster.hrl").
start(Opts) -> start(Host, Opts) ->
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
mnesia:create_table(roster,[{disc_copies, [node()]}, mnesia:create_table(roster,[{disc_copies, [node()]},
{attributes, record_info(fields, roster)}]), {attributes, record_info(fields, roster)}]),
update_table(), update_table(),
mnesia:add_table_index(roster, us), mnesia:add_table_index(roster, us),
ejabberd_hooks:add(roster_get, ejabberd_hooks:add(roster_get, Host,
?MODULE, get_user_roster, 50), ?MODULE, get_user_roster, 50),
ejabberd_hooks:add(roster_in_subscription, ejabberd_hooks:add(roster_in_subscription, Host,
?MODULE, in_subscription, 50), ?MODULE, in_subscription, 50),
ejabberd_hooks:add(roster_out_subscription, ejabberd_hooks:add(roster_out_subscription, Host,
?MODULE, out_subscription, 50), ?MODULE, out_subscription, 50),
ejabberd_hooks:add(roster_get_subscription_lists, ejabberd_hooks:add(roster_get_subscription_lists, Host,
?MODULE, get_subscription_lists, 50), ?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), ?MODULE, get_jid_info, 50),
ejabberd_hooks:add(remove_user, ejabberd_hooks:add(remove_user, Host,
?MODULE, remove_user, 50), ?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). ?MODULE, process_iq, IQDisc).
stop() -> stop(Host) ->
ejabberd_hooks:delete(roster_get, ejabberd_hooks:delete(roster_get, Host,
?MODULE, get_user_roster, 50), ?MODULE, get_user_roster, 50),
ejabberd_hooks:delete(roster_in_subscription, ejabberd_hooks:delete(roster_in_subscription, Host,
?MODULE, in_subscription, 50), ?MODULE, in_subscription, 50),
ejabberd_hooks:delete(roster_out_subscription, ejabberd_hooks:delete(roster_out_subscription, Host,
?MODULE, out_subscription, 50), ?MODULE, out_subscription, 50),
ejabberd_hooks:delete(roster_get_subscription_lists, ejabberd_hooks:delete(roster_get_subscription_lists, Host,
?MODULE, get_subscription_lists, 50), ?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), ?MODULE, get_jid_info, 50),
ejabberd_hooks:delete(remove_user, ejabberd_hooks:delete(remove_user, Host,
?MODULE, remove_user, 50), ?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). -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, LUser = From#jid.luser,
LServer = From#jid.lserver, LServer = From#jid.lserver,
US = {LUser, 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) -> Items when is_list(Items) ->
XItems = lists:map(fun item_to_xml/1, Items), XItems = lists:map(fun item_to_xml/1, Items),
IQ#iq{type = result, IQ#iq{type = result,

View File

@ -12,7 +12,7 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/1, stop/0, -export([start/2, stop/1,
process_iq/3, process_iq/3,
process_local_iq/3, process_local_iq/3,
get_subscription_lists/2, get_subscription_lists/2,
@ -31,35 +31,35 @@
subscription = none, subscription = none,
ask = none}). ask = none}).
start(Opts) -> start(Host, Opts) ->
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), 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), ?MODULE, out_subscription, 50),
ejabberd_hooks:add(roster_in_subscription, ejabberd_hooks:add(roster_in_subscription, Host,
?MODULE, in_subscription, 50), ?MODULE, in_subscription, 50),
ejabberd_hooks:add(roster_out_subscription, ejabberd_hooks:add(roster_out_subscription, Host,
?MODULE, out_subscription, 50), ?MODULE, out_subscription, 50),
ejabberd_hooks:add(roster_get_subscription_lists, ejabberd_hooks:add(roster_get_subscription_lists, Host,
?MODULE, get_subscription_lists, 50), ?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), ?MODULE, get_jid_info, 50),
ejabberd_hooks:add(remove_user, ejabberd_hooks:add(remove_user, Host,
?MODULE, remove_user, 50), ?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). ?MODULE, process_iq, IQDisc).
stop() -> stop(Host) ->
ejabberd_hooks:delete(roster_in_subscription, ejabberd_hooks:delete(roster_in_subscription, Host,
?MODULE, in_subscription, 50), ?MODULE, in_subscription, 50),
ejabberd_hooks:delete(roster_out_subscription, ejabberd_hooks:delete(roster_out_subscription, Host,
?MODULE, out_subscription, 50), ?MODULE, out_subscription, 50),
ejabberd_hooks:delete(roster_get_subscription_lists, ejabberd_hooks:delete(roster_get_subscription_lists, Host,
?MODULE, get_subscription_lists, 50), ?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), ?MODULE, get_jid_info, 50),
ejabberd_hooks:delete(remove_user, ejabberd_hooks:delete(remove_user, Host,
?MODULE, remove_user, 50), ?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). -define(PSI_ROSTER_WORKAROUND, true).

View File

@ -11,25 +11,25 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/1, -export([start/2,
stop/0, stop/1,
log_user_send/3, log_user_send/3,
log_user_receive/4]). log_user_receive/4]).
-include("ejabberd.hrl"). -include("ejabberd.hrl").
-include("jlib.hrl"). -include("jlib.hrl").
start(_) -> start(Host, _Opts) ->
ejabberd_hooks:add(user_send_packet, ejabberd_hooks:add(user_send_packet, Host,
?MODULE, log_user_send, 50), ?MODULE, log_user_send, 50),
ejabberd_hooks:add(user_receive_packet, ejabberd_hooks:add(user_receive_packet, Host,
?MODULE, log_user_receive, 50), ?MODULE, log_user_receive, 50),
ok. ok.
stop() -> stop(Host) ->
ejabberd_hooks:delete(user_send_packet, ejabberd_hooks:delete(user_send_packet, Host,
?MODULE, log_user_send, 50), ?MODULE, log_user_send, 50),
ejabberd_hooks:delete(user_receive_packet, ejabberd_hooks:delete(user_receive_packet, Host,
?MODULE, log_user_receive, 50), ?MODULE, log_user_receive, 50),
ok. ok.
@ -41,9 +41,10 @@ log_user_receive(_JID, From, To, Packet) ->
log_packet(From, To, {xmlelement, Name, Attrs, Els}) -> log_packet(From, To, {xmlelement, Name, Attrs, Els}) ->
Loggers = gen_mod:get_module_opt(?MODULE, loggers, []), Host = From#jid.lserver,
ServerJID = #jid{user = "", server = ?MYNAME, resource = "", Loggers = gen_mod:get_module_opt(Host, ?MODULE, loggers, []),
luser = "", lserver = ?MYNAME, lresource = ""}, ServerJID = #jid{user = "", server = Host, resource = "",
luser = "", lserver = Host, lresource = ""},
NewAttrs = jlib:replace_from_to_attrs(jlib:jid_to_string(From), NewAttrs = jlib:replace_from_to_attrs(jlib:jid_to_string(From),
jlib:jid_to_string(To), jlib:jid_to_string(To),
Attrs), Attrs),

View File

@ -12,7 +12,7 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/1, stop/0, -export([start/2, stop/1,
get_user_roster/2, get_user_roster/2,
get_subscription_lists/3, get_subscription_lists/3,
get_jid_info/4, get_jid_info/4,
@ -35,7 +35,7 @@
-record(sr_group, {group_host, opts}). -record(sr_group, {group_host, opts}).
-record(sr_user, {us, group_host}). -record(sr_user, {us, group_host}).
start(_Opts) -> start(Host, _Opts) ->
mnesia:create_table(sr_group, mnesia:create_table(sr_group,
[{disc_copies, [node()]}, [{disc_copies, [node()]},
{attributes, record_info(fields, sr_group)}]), {attributes, record_info(fields, sr_group)}]),
@ -44,31 +44,31 @@ start(_Opts) ->
{type, bag}, {type, bag},
{attributes, record_info(fields, sr_user)}]), {attributes, record_info(fields, sr_user)}]),
mnesia:add_table_index(sr_user, group_host), mnesia:add_table_index(sr_user, group_host),
ejabberd_hooks:add(roster_get, ejabberd_hooks:add(roster_get, Host,
?MODULE, get_user_roster, 70), ?MODULE, get_user_roster, 70),
ejabberd_hooks:add(roster_in_subscription, ejabberd_hooks:add(roster_in_subscription, Host,
?MODULE, in_subscription, 30), ?MODULE, in_subscription, 30),
ejabberd_hooks:add(roster_out_subscription, ejabberd_hooks:add(roster_out_subscription, Host,
?MODULE, out_subscription, 30), ?MODULE, out_subscription, 30),
ejabberd_hooks:add(roster_get_subscription_lists, ejabberd_hooks:add(roster_get_subscription_lists, Host,
?MODULE, get_subscription_lists, 70), ?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). ?MODULE, get_jid_info, 70).
%ejabberd_hooks:add(remove_user, %ejabberd_hooks:add(remove_user, Host,
% ?MODULE, remove_user, 50), % ?MODULE, remove_user, 50),
stop() -> stop(Host) ->
ejabberd_hooks:delete(roster_get, ejabberd_hooks:delete(roster_get, Host,
?MODULE, get_user_roster, 70), ?MODULE, get_user_roster, 70),
ejabberd_hooks:delete(roster_in_subscription, ejabberd_hooks:delete(roster_in_subscription, Host,
?MODULE, in_subscription, 30), ?MODULE, in_subscription, 30),
ejabberd_hooks:delete(roster_out_subscription, ejabberd_hooks:delete(roster_out_subscription, Host,
?MODULE, out_subscription, 30), ?MODULE, out_subscription, 30),
ejabberd_hooks:delete(roster_get_subscription_lists, ejabberd_hooks:delete(roster_get_subscription_lists, Host,
?MODULE, get_subscription_lists, 70), ?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). ?MODULE, get_jid_info, 70).
%ejabberd_hooks:delete(remove_user, %ejabberd_hooks:delete(remove_user, Host,
% ?MODULE, remove_user, 50), % ?MODULE, remove_user, 50),

View File

@ -12,19 +12,19 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/1, -export([start/2,
stop/0, stop/1,
process_local_iq/3]). process_local_iq/3]).
-include("jlib.hrl"). -include("jlib.hrl").
start(Opts) -> start(Host, Opts) ->
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), 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). ?MODULE, process_local_iq, IQDisc).
stop() -> stop(Host) ->
gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_STATS). gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_STATS).
process_local_iq(From, To, #iq{id = ID, type = Type, process_local_iq(From, To, #iq{id = ID, type = Type,

View File

@ -12,21 +12,21 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/1, -export([start/2,
stop/0, stop/1,
process_local_iq/3]). process_local_iq/3]).
-include("ejabberd.hrl"). -include("ejabberd.hrl").
-include("jlib.hrl"). -include("jlib.hrl").
start(Opts) -> start(Host, Opts) ->
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), 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). ?MODULE, process_local_iq, IQDisc).
stop() -> stop(Host) ->
gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_TIME). gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_TIME).
process_local_iq(_From, _To, #iq{type = Type, sub_el = SubEl} = IQ) -> process_local_iq(_From, _To, #iq{type = Type, sub_el = SubEl} = IQ) ->
case Type of case Type of

View File

@ -12,7 +12,7 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/1, init/2, stop/0, -export([start/2, init/2, stop/1,
process_local_iq/3, process_local_iq/3,
process_sm_iq/3, process_sm_iq/3,
reindex_vcards/0, reindex_vcards/0,
@ -40,8 +40,9 @@
}). }).
-record(vcard, {us, vcard}). -record(vcard, {us, vcard}).
-define(PROCNAME, ejabberd_mod_vcard).
start(Opts) -> start(Host, Opts) ->
mnesia:create_table(vcard, [{disc_only_copies, [node()]}, mnesia:create_table(vcard, [{disc_only_copies, [node()]},
{attributes, record_info(fields, vcard)}]), {attributes, record_info(fields, vcard)}]),
mnesia:create_table(vcard_search, mnesia:create_table(vcard_search,
@ -61,17 +62,18 @@ start(Opts) ->
mnesia:add_table_index(vcard_search, lorgname), mnesia:add_table_index(vcard_search, lorgname),
mnesia:add_table_index(vcard_search, lorgunit), mnesia:add_table_index(vcard_search, lorgunit),
ejabberd_hooks:add(remove_user, ejabberd_hooks:add(remove_user, Host,
?MODULE, remove_user, 50), ?MODULE, remove_user, 50),
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), 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), ?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), ?MODULE, process_sm_iq, IQDisc),
catch mod_disco:register_sm_feature(?NS_VCARD), catch mod_disco:register_sm_feature(?NS_VCARD),
Hosts = gen_mod:get_hosts(Opts, "vjud."), Hosts = gen_mod:get_hosts(Opts, "vjud."),
Search = gen_mod:get_opt(search, Opts, true), 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) -> init(Hosts, Search) ->
@ -100,14 +102,15 @@ loop(Hosts) ->
loop(Hosts) loop(Hosts)
end. end.
stop() -> stop(Host) ->
ejabberd_hooks:delete(remove_user, ejabberd_hooks:delete(remove_user, Host,
?MODULE, remove_user, 50), ?MODULE, remove_user, 50),
gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_VCARD), gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_VCARD),
gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_VCARD), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_VCARD),
catch mod_disco:unregister_sm_feature(?NS_VCARD), catch mod_disco:unregister_sm_feature(Host, ?NS_VCARD),
ejabberd_mod_vcard ! stop, Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
ok. Proc ! stop,
{wait, Proc}.
process_local_iq(_From, _To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> process_local_iq(_From, _To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) ->
case Type of case Type of
@ -463,7 +466,8 @@ record_to_item(R) ->
search(LServer, Data) -> search(LServer, Data) ->
MatchSpec = make_matchspec(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 if
(MatchSpec == #vcard_search{_ = '_'}) and (not AllowReturnAll) -> (MatchSpec == #vcard_search{_ = '_'}) and (not AllowReturnAll) ->
[]; [];
@ -474,7 +478,8 @@ search(LServer, Data) ->
?ERROR_MSG("~p", [Reason]), ?ERROR_MSG("~p", [Reason]),
[]; [];
Rs -> 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 -> infinity ->
Rs; Rs;
Val when is_integer(Val) and (Val > 0) -> Val when is_integer(Val) and (Val > 0) ->
@ -501,8 +506,8 @@ filter_fields([{SVar, [Val]} | Ds], Match, LServer)
LVal = stringprep:tolower(Val), LVal = stringprep:tolower(Val),
NewMatch = case SVar of NewMatch = case SVar of
"user" -> "user" ->
case gen_mod:get_module_opt( case gen_mod:get_module_opt(LServer, ?MODULE,
?MODULE, search_all_hosts, true) of search_all_hosts, true) of
true -> true ->
Match#vcard_search{luser = make_val(LVal)}; Match#vcard_search{luser = make_val(LVal)};
false -> false ->

View File

@ -12,7 +12,7 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/1, init/2, stop/0, -export([start/2, init/2, stop/1,
process_local_iq/3, process_local_iq/3,
process_sm_iq/3, process_sm_iq/3,
remove_user/1]). remove_user/1]).
@ -22,11 +22,11 @@
-include("jlib.hrl"). -include("jlib.hrl").
start(Opts) -> start(Host, Opts) ->
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), 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), ?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), ?MODULE, process_sm_iq, IQDisc),
LDAPServers = ejabberd_config:get_local_option(ldap_servers), LDAPServers = ejabberd_config:get_local_option(ldap_servers),
RootDN = ejabberd_config:get_local_option(ldap_rootdn), RootDN = ejabberd_config:get_local_option(ldap_rootdn),
@ -62,9 +62,9 @@ loop(Host) ->
loop(Host) loop(Host)
end. end.
stop() -> stop(Host) ->
gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_VCARD), gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_VCARD),
gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_VCARD), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_VCARD),
ejabberd_mod_vcard_ldap ! stop, ejabberd_mod_vcard_ldap ! stop,
ok. ok.

View File

@ -12,8 +12,8 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/1, -export([start/2,
stop/0, stop/1,
process_local_iq/3]). process_local_iq/3]).
-include("ejabberd.hrl"). -include("ejabberd.hrl").
@ -21,13 +21,13 @@
start(Opts) -> start(Host, Opts) ->
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), 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). ?MODULE, process_local_iq, IQDisc).
stop() -> stop(Host) ->
gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_VERSION). gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_VERSION).
process_local_iq(From, To, #iq{id = ID, type = Type, process_local_iq(From, To, #iq{id = ID, type = Type,

View File

@ -49,6 +49,34 @@ make_xhtml(Els) ->
{"value", Value}])). {"value", Value}])).
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}, process_get({_, true},
#request{us = US, #request{us = US,
path = ["admin" | RPath], path = ["admin" | RPath],
@ -56,12 +84,13 @@ process_get({_, true},
lang = Lang} = Request) -> lang = Lang} = Request) ->
case US of case US of
{User, Server} -> {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 -> deny ->
{401, [], make_xhtml([?XC("h1", "Not Allowed")])}; {401, [], make_xhtml([?XC("h1", "Not Allowed")])};
allow -> allow ->
ejabberd_web_admin:process_admin( ejabberd_web_admin:process_admin(
Request#request{path = RPath}) global, Request#request{path = RPath})
end; end;
undefined -> undefined ->
{401, {401,

View File

@ -14,7 +14,7 @@
-vsn('$Revision$ '). -vsn('$Revision$ ').
%% External exports %% External exports
-export([process_admin/1]). -export([process_admin/2]).
-include("ejabberd.hrl"). -include("ejabberd.hrl").
-include("jlib.hrl"). -include("jlib.hrl").
@ -52,7 +52,7 @@
{"size", Size}])). {"size", Size}])).
-define(INPUTST(Type, Name, Value, Size), ?INPUT(Type, Name, ?T(Value), Size)). -define(INPUTST(Type, Name, Value, Size), ?INPUT(Type, Name, ?T(Value), Size)).
make_xhtml(Els, Lang) -> make_xhtml(Els, global, Lang) ->
{200, [html], {200, [html],
{xmlelement, "html", [{"xmlns", "http://www.w3.org/1999/xhtml"}, {xmlelement, "html", [{"xmlns", "http://www.w3.org/1999/xhtml"},
{"xml:lang", Lang}, {"xml:lang", Lang},
@ -76,16 +76,60 @@ make_xhtml(Els, Lang) ->
[?XE("ul", [?XE("ul",
[?LI([?ACT("/admin/acls/", "Access Control Lists")]), [?LI([?ACT("/admin/acls/", "Access Control Lists")]),
?LI([?ACT("/admin/access/", "Access Rules")]), ?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/nodes/", "Nodes")]),
?LI([?ACT("/admin/stats/", "Statistics")]) ?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, case lists:member(mod_shared_roster,
gen_mod:loaded_modules()) of gen_mod:loaded_modules(Host)) of
true -> true ->
[?LI([?ACT("/admin/shared-roster/", "Shared Roster")])]; [?LI([?ACT(Base ++ "shared-roster/", "Shared Roster")])];
false -> false ->
[] []
end end
@ -105,7 +149,14 @@ make_xhtml(Els, Lang) ->
])])]) ])])])
]}}. ]}}.
css() -> " css(Host) ->
Base = case Host of
global ->
"/admin/";
_ ->
"/admin/server/" ++ Host ++ "/"
end,
"
html,body { html,body {
background: white; background: white;
margin: 0; margin: 0;
@ -130,7 +181,7 @@ html>body #container {
height: 55px; height: 55px;
padding: 0; padding: 0;
margin: 0; margin: 0;
background: transparent url(\"/admin/logo-fill.png\"); background: transparent url(\"" ++ Base ++ "logo-fill.png\");
} }
#header h1 a { #header h1 a {
@ -141,7 +192,7 @@ html>body #container {
height: 55px; height: 55px;
padding: 0; padding: 0;
margin: 0; margin: 0;
background: transparent url(\"/admin/logo.png\") no-repeat; background: transparent url(\"" ++ Base ++ "logo.png\") no-repeat;
display: block; display: block;
text-indent: -700em; text-indent: -700em;
} }
@ -466,7 +517,8 @@ logo_fill() ->
"1c5dvhSU2BpKqBXl6R0ljYGS50R5zVC+tVD+vfE6YyUexE9x7g4AAAAASUVO" "1c5dvhSU2BpKqBXl6R0ljYGS50R5zVC+tVD+vfE6YyUexE9x7g4AAAAASUVO"
"RK5CYII="). "RK5CYII=").
process_admin(#request{us = US, process_admin(global,
#request{us = US,
path = [], path = [],
q = Query, q = Query,
lang = Lang} = Request) -> lang = Lang} = Request) ->
@ -476,41 +528,63 @@ process_admin(#request{us = US,
?ACT("/admin/acls-raw/", "(raw)")]), ?ACT("/admin/acls-raw/", "(raw)")]),
?LI([?ACT("/admin/access/", "Access Rules"), ?C(" "), ?LI([?ACT("/admin/access/", "Access Rules"), ?C(" "),
?ACT("/admin/access-raw/", "(raw)")]), ?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/nodes/", "Nodes")]),
?LI([?ACT("/admin/stats/", "Statistics")]) ?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, case lists:member(mod_shared_roster,
gen_mod:loaded_modules()) of gen_mod:loaded_modules(Host)) of
true -> true ->
[?LI([?ACT("/admin/shared-roster/", "Shared Roster")])]; [?LI([?ACT(Base ++ "shared-roster/", "Shared Roster")])];
false -> false ->
[] []
end end
) )
], Lang); ], Host, Lang);
process_admin(#request{us = US, process_admin(Host,
#request{us = US,
path = ["style.css"], path = ["style.css"],
q = Query, q = Query,
lang = Lang} = Request) -> 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"], path = ["logo.png"],
q = Query, q = Query,
lang = Lang} = Request) -> lang = Lang} = Request) ->
{200, [{"Content-Type", "image/png"}], logo()}; {200, [{"Content-Type", "image/png"}], logo()};
process_admin(#request{us = US, process_admin(Host,
#request{us = US,
path = ["logo-fill.png"], path = ["logo-fill.png"],
q = Query, q = Query,
lang = Lang} = Request) -> lang = Lang} = Request) ->
{200, [{"Content-Type", "image/png"}], logo_fill()}; {200, [{"Content-Type", "image/png"}], logo_fill()};
process_admin(#request{us = US, process_admin(Host,
#request{us = US,
path = ["acls-raw"], path = ["acls-raw"],
q = Query, q = Query,
lang = Lang} = Request) -> lang = Lang} = Request) ->
@ -520,7 +594,7 @@ process_admin(#request{us = US,
{ok, Tokens, _} -> {ok, Tokens, _} ->
case erl_parse:parse_term(Tokens) of case erl_parse:parse_term(Tokens) of
{ok, NewACLs} -> {ok, NewACLs} ->
case acl:add_list(NewACLs, true) of case acl:add_list(Host, NewACLs, true) of
ok -> ok ->
ok; ok;
_ -> _ ->
@ -535,7 +609,11 @@ process_admin(#request{us = US,
_ -> _ ->
nothing nothing
end, 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")] ++ make_xhtml([?XCT("h1", "ejabberd access control lists configuration")] ++
case Res of case Res of
ok -> [?CT("submitted"), ?P]; ok -> [?CT("submitted"), ?P];
@ -550,9 +628,10 @@ process_admin(#request{us = US,
?BR, ?BR,
?INPUTT("submit", "submit", "Submit") ?INPUTT("submit", "submit", "Submit")
]) ])
], Lang); ], Host, Lang);
process_admin(#request{method = Method, process_admin(Host,
#request{method = Method,
us = US, us = US,
path = ["acls"], path = ["acls"],
q = Query, q = Query,
@ -560,12 +639,12 @@ process_admin(#request{method = Method,
?INFO_MSG("query: ~p", [Query]), ?INFO_MSG("query: ~p", [Query]),
Res = case Method of Res = case Method of
'POST' -> 'POST' ->
case catch acl_parse_query(Query) of case catch acl_parse_query(Host, Query) of
{'EXIT', _} -> {'EXIT', _} ->
error; error;
NewACLs -> NewACLs ->
?INFO_MSG("NewACLs: ~p", [NewACLs]), ?INFO_MSG("NewACLs at ~s: ~p", [Host, NewACLs]),
case acl:add_list(NewACLs, true) of case acl:add_list(Host, NewACLs, true) of
ok -> ok ->
?INFO_MSG("NewACLs: ok", []), ?INFO_MSG("NewACLs: ok", []),
ok; ok;
@ -576,7 +655,9 @@ process_admin(#request{method = Method,
_ -> _ ->
nothing nothing
end, 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")] ++ make_xhtml([?XCT("h1", "ejabberd access control lists configuration")] ++
case Res of case Res of
ok -> [?CT("submitted"), ?P]; ok -> [?CT("submitted"), ?P];
@ -591,9 +672,10 @@ process_admin(#request{method = Method,
?C(" "), ?C(" "),
?INPUTT("submit", "submit", "Submit") ?INPUTT("submit", "submit", "Submit")
]) ])
], Lang); ], Host, Lang);
process_admin(#request{us = US, process_admin(Host,
#request{us = US,
path = ["access-raw"], path = ["access-raw"],
q = Query, q = Query,
lang = Lang} = Request) -> lang = Lang} = Request) ->
@ -601,8 +683,9 @@ process_admin(#request{us = US,
fun(Rs) -> fun(Rs) ->
mnesia:transaction( mnesia:transaction(
fun() -> fun() ->
Os = mnesia:select(config, Os = mnesia:select(
[{{config, {access, '$1'}, '$2'}, config,
[{{config, {access, '$1', Host}, '$2'},
[], [],
['$_']}]), ['$_']}]),
lists:foreach(fun(O) -> lists:foreach(fun(O) ->
@ -611,7 +694,7 @@ process_admin(#request{us = US,
lists:foreach( lists:foreach(
fun({access, Name, Rules}) -> fun({access, Name, Rules}) ->
mnesia:write({config, mnesia:write({config,
{access, Name}, {access, Name, Host},
Rules}) Rules})
end, Rs) end, Rs)
end) end)
@ -641,7 +724,7 @@ process_admin(#request{us = US,
lists:flatten( lists:flatten(
io_lib:format( io_lib:format(
"~p.", [ets:select(config, "~p.", [ets:select(config,
[{{config, {access, '$1'}, '$2'}, [{{config, {access, '$1', Host}, '$2'},
[], [],
[{{access, '$1', '$2'}}]}])])), [{{access, '$1', '$2'}}]}])])),
make_xhtml([?XCT("h1", "ejabberd access rules configuration")] ++ make_xhtml([?XCT("h1", "ejabberd access rules configuration")] ++
@ -658,9 +741,10 @@ process_admin(#request{us = US,
?BR, ?BR,
?INPUTT("submit", "submit", "Submit") ?INPUTT("submit", "submit", "Submit")
]) ])
], Lang); ], Host, Lang);
process_admin(#request{method = Method, process_admin(Host,
#request{method = Method,
us = US, us = US,
path = ["access"], path = ["access"],
q = Query, q = Query,
@ -668,7 +752,7 @@ process_admin(#request{method = Method,
?INFO_MSG("query: ~p", [Query]), ?INFO_MSG("query: ~p", [Query]),
Res = case Method of Res = case Method of
'POST' -> 'POST' ->
case catch access_parse_query(Query) of case catch access_parse_query(Host, Query) of
{'EXIT', _} -> {'EXIT', _} ->
error; error;
ok -> ok ->
@ -679,7 +763,7 @@ process_admin(#request{method = Method,
end, end,
AccessRules = AccessRules =
ets:select(config, ets:select(config,
[{{config, {access, '$1'}, '$2'}, [{{config, {access, '$1', Host}, '$2'},
[], [],
[{{access, '$1', '$2'}}]}]), [{{access, '$1', '$2'}}]}]),
make_xhtml([?XCT("h1", "ejabberd access rules configuration")] ++ make_xhtml([?XCT("h1", "ejabberd access rules configuration")] ++
@ -694,9 +778,10 @@ process_admin(#request{method = Method,
?BR, ?BR,
?INPUTT("submit", "delete", "Delete Selected") ?INPUTT("submit", "delete", "Delete Selected")
]) ])
], Lang); ], Host, Lang);
process_admin(#request{method = Method, process_admin(Host,
#request{method = Method,
us = US, us = US,
path = ["access", SName], path = ["access", SName],
q = Query, q = Query,
@ -708,7 +793,7 @@ process_admin(#request{method = Method,
case parse_access_rule(String) of case parse_access_rule(String) of
{ok, Rs} -> {ok, Rs} ->
ejabberd_config:add_global_option( ejabberd_config:add_global_option(
{access, Name}, Rs), {access, Name, Host}, Rs),
ok; ok;
_ -> _ ->
error error
@ -716,7 +801,7 @@ process_admin(#request{method = Method,
_ -> _ ->
nothing nothing
end, end,
Rules = case ejabberd_config:get_global_option({access, Name}) of Rules = case ejabberd_config:get_global_option({access, Name, Host}) of
undefined -> undefined ->
[]; [];
Rs1 -> Rs1 ->
@ -734,34 +819,38 @@ process_admin(#request{method = Method,
?BR, ?BR,
?INPUTT("submit", "submit", "Submit") ?INPUTT("submit", "submit", "Submit")
]) ])
], Lang); ], Host, Lang);
process_admin(#request{us = US, process_admin(Host,
#request{us = US,
path = ["users"], path = ["users"],
q = Query, q = Query,
lang = Lang} = Request) -> lang = Lang} = Request) when is_list(Host) ->
Res = list_users(Query, Lang), Res = list_users(Host, Query, Lang),
make_xhtml([?XCT("h1", "ejabberd users")] ++ Res, Lang); make_xhtml([?XCT("h1", "ejabberd users")] ++ Res, Host, Lang);
process_admin(#request{us = US, process_admin(Host,
#request{us = US,
path = ["users", Diap], path = ["users", Diap],
q = Query, q = Query,
lang = Lang} = Request) -> lang = Lang} = Request) when is_list(Host) ->
Res = list_users_in_diapason(Diap, Lang), Res = list_users_in_diapason(Host, Diap, Lang),
make_xhtml([?XCT("h1", "ejabberd users")] ++ Res, Lang); make_xhtml([?XCT("h1", "ejabberd users")] ++ Res, Host, Lang);
process_admin(#request{us = US, process_admin(Host,
#request{us = US,
path = ["online-users"], path = ["online-users"],
q = Query, q = Query,
lang = Lang} = Request) -> lang = Lang} = Request) when is_list(Host) ->
Res = list_online_users(Lang), Res = list_online_users(Host, Lang),
make_xhtml([?XCT("h1", "ejabberd users")] ++ Res, Lang); make_xhtml([?XCT("h1", "ejabberd users")] ++ Res, Host, Lang);
process_admin(#request{method = Method, process_admin(Host,
#request{method = Method,
us = US, us = US,
path = ["last-activity"], path = ["last-activity"],
q = Query, q = Query,
lang = Lang} = Request) -> lang = Lang} = Request) when is_list(Host) ->
?INFO_MSG("query: ~p", [Query]), ?INFO_MSG("query: ~p", [Query]),
Month = case lists:keysearch("period", 1, Query) of Month = case lists:keysearch("period", 1, Query) of
{value, {_, Val}} -> {value, {_, Val}} ->
@ -771,9 +860,9 @@ process_admin(#request{method = Method,
end, end,
Res = case lists:keysearch("ordinary", 1, Query) of Res = case lists:keysearch("ordinary", 1, Query) of
{value, {_, _}} -> {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, end,
make_xhtml([?XCT("h1", "Users last activity")] ++ make_xhtml([?XCT("h1", "Users last activity")] ++
[?XAE("form", [{"method", "post"}], [?XAE("form", [{"method", "post"}],
@ -795,71 +884,80 @@ process_admin(#request{method = Method,
?C(" "), ?C(" "),
?INPUTT("submit", "integral", "Show Integral Table") ?INPUTT("submit", "integral", "Show Integral Table")
])] ++ ])] ++
Res, Lang); Res, Host, Lang);
process_admin(#request{us = US, process_admin(Host,
#request{us = US,
path = ["stats"], path = ["stats"],
q = Query, q = Query,
lang = Lang} = Request) -> lang = Lang} = Request) ->
Res = get_stats(Lang), Res = get_stats(Host, Lang),
make_xhtml([?XCT("h1", "ejabberd stats")] ++ Res, Lang); make_xhtml([?XCT("h1", "ejabberd stats")] ++ Res, Host, Lang);
process_admin(#request{us = US, process_admin(Host,
#request{us = US,
path = ["user", U], path = ["user", U],
q = Query, q = Query,
lang = Lang} = Request) -> lang = Lang} = Request) ->
Res = user_info(U, Query, Lang), Res = user_info(U, Host, Query, Lang),
make_xhtml(Res, Lang); make_xhtml(Res, Host, Lang);
process_admin(#request{us = US, process_admin(Host,
#request{us = US,
path = ["user", U, "queue"], path = ["user", U, "queue"],
q = Query, q = Query,
lang = Lang} = Request) -> lang = Lang} = Request) ->
Res = user_queue(U, Query, Lang), Res = user_queue(U, Host, Query, Lang),
make_xhtml(Res, Lang); make_xhtml(Res, Host, Lang);
process_admin(#request{us = US, process_admin(Host,
#request{us = US,
path = ["user", U, "roster"], path = ["user", U, "roster"],
q = Query, q = Query,
lang = Lang} = Request) -> lang = Lang} = Request) ->
Res = user_roster(U, Query, Lang, true), Res = user_roster(U, Host, Query, Lang, true),
make_xhtml(Res, Lang); make_xhtml(Res, Host, Lang);
process_admin(#request{us = US, process_admin(Host,
#request{us = US,
path = ["nodes"], path = ["nodes"],
q = Query, q = Query,
lang = Lang} = Request) -> lang = Lang} = Request) ->
Res = get_nodes(Lang), 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], path = ["node", SNode | NPath],
q = Query, q = Query,
lang = Lang} = Request) -> lang = Lang} = Request) ->
case search_running_node(SNode) of case search_running_node(SNode) of
false -> false ->
make_xhtml([?XCT("h1", "Node not found")], Lang); make_xhtml([?XCT("h1", "Node not found")], Host, Lang);
Node -> Node ->
Res = get_node(Node, NPath, Query, Lang), Res = get_node(Host, Node, NPath, Query, Lang),
make_xhtml(Res, Lang) make_xhtml(Res, Host, Lang)
end; end;
process_admin(#request{us = US, process_admin(Host,
#request{us = US,
path = ["shared-roster"], path = ["shared-roster"],
q = Query, q = Query,
lang = Lang} = Request) -> lang = Lang} = Request) ->
Res = list_shared_roster_groups(Query, Lang), 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], path = ["shared-roster", Group],
q = Query, q = Query,
lang = Lang} = Request) -> lang = Lang} = Request) ->
Res = shared_roster_group(Group, Query, Lang), Res = shared_roster_group(Group, Query, Lang),
make_xhtml(Res, Lang); make_xhtml(Res, Host, Lang);
process_admin(#request{lang = Lang}) -> process_admin(Host,
setelement(1, make_xhtml([?XC("h1", "Not found")], Lang), 404). #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))). jlib:encode_base64(binary_to_list(term_to_binary(T))).
acl_parse_query(Query) -> acl_parse_query(Host, Query) ->
ACLs = ets:tab2list(acl), ACLs = ets:select(acl, [{{acl, {'$1', Host}, '$2'},
[], [{{acl, '$1', '$2'}}]}]),
case lists:keysearch("submit", 1, Query) of case lists:keysearch("submit", 1, Query) of
{value, _} -> {value, _} ->
acl_parse_submit(ACLs, Query); acl_parse_submit(ACLs, Query);
@ -977,7 +1076,7 @@ string_to_spec("server", Val) ->
{server, Val}; {server, Val};
string_to_spec("user_server", Val) -> string_to_spec("user_server", Val) ->
#jid{luser = U, lserver = S, resource = ""} = jlib:string_to_jid(Val), #jid{luser = U, lserver = S, resource = ""} = jlib:string_to_jid(Val),
{user_server, U, S}; {user, U, S};
string_to_spec("raw", Val) -> string_to_spec("raw", Val) ->
{ok, Tokens, _} = erl_scan:string(Val ++ "."), {ok, Tokens, _} = erl_scan:string(Val ++ "."),
{ok, NewSpec} = erl_parse:parse_term(Tokens), {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 = AccessRules =
ets:select(config, ets:select(config,
[{{config, {access, '$1'}, '$2'}, [{{config, {access, '$1', Host}, '$2'},
[], [],
[{{access, '$1', '$2'}}]}]), [{{access, '$1', '$2'}}]}]),
case lists:keysearch("addnew", 1, Query) of case lists:keysearch("addnew", 1, Query) of
{value, _} -> {value, _} ->
access_parse_addnew(AccessRules, Query); access_parse_addnew(AccessRules, Host, Query);
_ -> _ ->
case lists:keysearch("delete", 1, Query) of case lists:keysearch("delete", 1, Query) of
{value, _} -> {value, _} ->
access_parse_delete(AccessRules, Query) access_parse_delete(AccessRules, Host, Query)
end end
end. end.
access_parse_addnew(AccessRules, Query) -> access_parse_addnew(AccessRules, Host, Query) ->
case lists:keysearch("namenew", 1, Query) of case lists:keysearch("namenew", 1, Query) of
{value, {_, String}} when String /= "" -> {value, {_, String}} when String /= "" ->
Name = list_to_atom(String), Name = list_to_atom(String),
ejabberd_config:add_global_option({access, Name}, []), ejabberd_config:add_global_option({access, Name, Host}, []),
ok ok
end. end.
access_parse_delete(AccessRules, Query) -> access_parse_delete(AccessRules, Host, Query) ->
lists:foreach( lists:foreach(
fun({access, Name, _Rules} = AccessRule) -> fun({access, Name, _Rules} = AccessRule) ->
ID = term_to_id(AccessRule), ID = term_to_id(AccessRule),
@ -1048,7 +1147,7 @@ access_parse_delete(AccessRules, Query) ->
true -> true ->
mnesia:transaction( mnesia:transaction(
fun() -> fun() ->
mnesia:delete({config, {access, Name}}) mnesia:delete({config, {access, Name, Host}})
end); end);
_ -> _ ->
ok ok
@ -1091,9 +1190,9 @@ parse_access_rule(Text) ->
list_users(Query, Lang) -> list_users(Host, Query, Lang) ->
Res = list_users_parse_query(Query), 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]), SUsers = lists:sort([{S, U} || {U, S} <- Users]),
FUsers = FUsers =
case length(SUsers) of case length(SUsers) of
@ -1162,8 +1261,8 @@ list_users_parse_query(Query) ->
end. end.
list_users_in_diapason(Diap, Lang) -> list_users_in_diapason(Host, Diap, Lang) ->
Users = ejabberd_auth:dirty_get_registered_users(), Users = ejabberd_auth:get_vh_registered_users(Host),
SUsers = lists:sort([{S, U} || {U, S} <- Users]), SUsers = lists:sort([{S, U} || {U, S} <- Users]),
{ok, [S1, S2]} = regexp:split(Diap, "-"), {ok, [S1, S2]} = regexp:split(Diap, "-"),
N1 = list_to_integer(S1), N1 = list_to_integer(S1),
@ -1184,7 +1283,7 @@ list_given_users(Users, Prefix, Lang) ->
US = {User, Server}, US = {User, Server},
QueueLen = length(mnesia:dirty_read({offline_msg, US})), QueueLen = length(mnesia:dirty_read({offline_msg, US})),
FQueueLen = [?AC(Prefix ++ "user/" ++ FQueueLen = [?AC(Prefix ++ "user/" ++
User ++ "@" ++ Server ++ "/queue/", User ++ "/queue/",
integer_to_list(QueueLen))], integer_to_list(QueueLen))],
FLast = FLast =
case ejabberd_sm:get_user_resources(User, Server) of case ejabberd_sm:get_user_resources(User, Server) of
@ -1208,8 +1307,7 @@ list_given_users(Users, Prefix, Lang) ->
?T("Online") ?T("Online")
end, end,
?XE("tr", ?XE("tr",
[?XE("td", [?AC(Prefix ++ "user/" ++ [?XE("td", [?AC(Prefix ++ "user/" ++ User ++ "/",
us_to_list(US) ++ "/",
us_to_list(US))]), us_to_list(US))]),
?XE("td", FQueueLen), ?XE("td", FQueueLen),
?XC("td", FLast)]) ?XC("td", FLast)])
@ -1223,14 +1321,13 @@ su_to_list({Server, User}) ->
jlib:jid_to_string({User, Server, ""}). jlib:jid_to_string({User, Server, ""}).
get_stats(Lang) -> get_stats(global, Lang) ->
OnlineUsers = mnesia:table_info(presence, size), OnlineUsers = mnesia:table_info(presence, size),
AuthUsers = mnesia:table_info(session, size), AuthUsers = mnesia:table_info(session, size),
RegisteredUsers = mnesia:table_info(passwd, size), RegisteredUsers = mnesia:table_info(passwd, size),
S2SConns = ejabberd_s2s:dirty_get_connections(), S2SConns = ejabberd_s2s:dirty_get_connections(),
S2SConnections = length(S2SConns), S2SConnections = length(S2SConns),
S2SServers = length(lists:usort([element(2, C) || C <- S2SConns])), S2SServers = length(lists:usort([element(2, C) || C <- S2SConns])),
[?XAE("table", [], [?XAE("table", [],
[?XE("tbody", [?XE("tbody",
[?XE("tr", [?XCT("td", "Registered users"), [?XE("tr", [?XCT("td", "Registered users"),
@ -1244,22 +1341,31 @@ get_stats(Lang) ->
?XE("tr", [?XCT("td", "Outgoing S2S servers"), ?XE("tr", [?XCT("td", "Outgoing S2S servers"),
?XC("td", integer_to_list(S2SServers))]) ?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) -> list_online_users(Host, _Lang) ->
Users = [{S, U} || {U, S, R} <- ejabberd_sm:dirty_get_sessions_list()], Users = [{S, U} || {U, S, R} <- ejabberd_sm:get_vh_session_list(Host)],
SUsers = lists:usort(Users), SUsers = lists:usort(Users),
lists:flatmap( lists:flatmap(
fun(SU) -> fun({S, U} = SU) ->
[?AC("../user/" ++ su_to_list(SU) ++ "/", su_to_list(SU)), ?BR] [?AC("../user/" ++ U ++ "/", su_to_list(SU)), ?BR]
end, SUsers). end, SUsers).
user_info(SUser, Query, Lang) -> user_info(User, Server, Query, Lang) ->
UJID = jlib:string_to_jid(SUser), US = {jlib:nodeprep(User), jlib:nameprep(Server)},
User = UJID#jid.user,
Server = UJID#jid.server,
US = {UJID#jid.luser, UJID#jid.lserver},
Res = user_parse_query(User, Server, Query), Res = user_parse_query(User, Server, Query),
Resources = ejabberd_sm:get_user_resources(User, Server), Resources = ejabberd_sm:get_user_resources(User, Server),
FResources = FResources =
@ -1315,11 +1421,8 @@ user_parse_query(User, Server, Query) ->
end. end.
user_queue(SUser, Query, Lang) -> user_queue(User, Server, Query, Lang) ->
UJID = jlib:string_to_jid(SUser), US = {jlib:nodeprep(User), jlib:nameprep(Server)},
User = UJID#jid.user,
Server = UJID#jid.server,
US = {UJID#jid.luser, UJID#jid.lserver},
Res = user_queue_parse_query(US, Query), Res = user_queue_parse_query(US, Query),
Msgs = lists:keysort(3, mnesia:dirty_read({offline_msg, US})), Msgs = lists:keysort(3, mnesia:dirty_read({offline_msg, US})),
FMsgs = FMsgs =
@ -1409,11 +1512,8 @@ ask_to_pending(unsubscribe) -> none;
ask_to_pending(Ask) -> Ask. ask_to_pending(Ask) -> Ask.
user_roster(SUser, Query, Lang, Admin) -> user_roster(User, Server, Query, Lang, Admin) ->
UJID = jlib:string_to_jid(SUser), US = {jlib:nodeprep(User), jlib:nameprep(Server)},
User = UJID#jid.user,
Server = UJID#jid.server,
US = {UJID#jid.luser, UJID#jid.lserver},
Items1 = mnesia:dirty_index_read(roster, US, #roster.us), Items1 = mnesia:dirty_index_read(roster, US, #roster.us),
Res = user_roster_parse_query(User, Server, Items1, Query, Admin), Res = user_roster_parse_query(User, Server, Items1, Query, Admin),
Items = mnesia:dirty_index_read(roster, US, #roster.us), Items = mnesia:dirty_index_read(roster, US, #roster.us),
@ -1556,7 +1656,7 @@ user_roster_item_parse_query(User, Server, Items, Query) ->
nothing. nothing.
list_last_activity(Lang, Integral, Period) -> list_last_activity(Host, Lang, Integral, Period) ->
{MegaSecs, Secs, _MicroSecs} = now(), {MegaSecs, Secs, _MicroSecs} = now(),
TimeStamp = MegaSecs * 1000000 + Secs, TimeStamp = MegaSecs * 1000000 + Secs,
case Period of case Period of
@ -1571,7 +1671,7 @@ list_last_activity(Lang, Integral, Period) ->
Days = 31 Days = 31
end, end,
case catch mnesia:dirty_select( case catch mnesia:dirty_select(
last_activity, [{{last_activity, '_', '$1', '_'}, last_activity, [{{last_activity, {'_', Host}, '$1', '_'},
[{'>', '$1', TS}], [{'>', '$1', TS}],
[{'trunc', {'/', [{'trunc', {'/',
{'-', TimeStamp, '$1'}, {'-', TimeStamp, '$1'},
@ -1677,7 +1777,7 @@ search_running_node(SNode, [Node | Nodes]) ->
search_running_node(SNode, Nodes) search_running_node(SNode, Nodes)
end. end.
get_node(Node, [], Query, Lang) -> get_node(global, Node, [], Query, Lang) ->
Res = node_parse_query(Node, Query), Res = node_parse_query(Node, Query),
[?XC("h1", ?T("Node ") ++ atom_to_list(Node))] ++ [?XC("h1", ?T("Node ") ++ atom_to_list(Node))] ++
case Res of case Res of
@ -1689,7 +1789,6 @@ get_node(Node, [], Query, Lang) ->
[?LI([?ACT("db/", "DB Management")]), [?LI([?ACT("db/", "DB Management")]),
?LI([?ACT("backup/", "Backup Management")]), ?LI([?ACT("backup/", "Backup Management")]),
?LI([?ACT("ports/", "Listened Ports Management")]), ?LI([?ACT("ports/", "Listened Ports Management")]),
?LI([?ACT("modules/", "Modules Management")]),
?LI([?ACT("stats/", "Statistics")]) ?LI([?ACT("stats/", "Statistics")])
]), ]),
?XAE("form", [{"method", "post"}], ?XAE("form", [{"method", "post"}],
@ -1698,7 +1797,13 @@ get_node(Node, [], Query, Lang) ->
?INPUTT("submit", "stop", "Stop")]) ?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 case rpc:call(Node, mnesia, system_info, [tables]) of
{badrpc, _Reason} -> {badrpc, _Reason} ->
[?XCT("h1", "RPC call error")]; [?XCT("h1", "RPC call error")];
@ -1765,7 +1870,7 @@ get_node(Node, ["db"], Query, Lang) ->
)])])] )])])]
end; end;
get_node(Node, ["backup"], Query, Lang) -> get_node(global, Node, ["backup"], Query, Lang) ->
Res = node_backup_parse_query(Node, Query), Res = node_backup_parse_query(Node, Query),
[?XC("h1", ?T("Backup Management at ") ++ atom_to_list(Node)), [?XC("h1", ?T("Backup Management at ") ++ atom_to_list(Node)),
?XAE("form", [{"method", "post"}], ?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]), Ports = rpc:call(Node, ejabberd_config, get_local_option, [listen]),
Res = case catch node_ports_parse_query(Node, Ports, Query) of Res = case catch node_ports_parse_query(Node, Ports, Query) of
submitted -> submitted ->
@ -1832,9 +1937,9 @@ get_node(Node, ["ports"], Query, Lang) ->
[node_ports_to_xhtml(NewPorts, 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, []), 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 -> submitted ->
ok; ok;
{'EXIT', Reason} -> {'EXIT', Reason} ->
@ -1843,7 +1948,8 @@ get_node(Node, ["modules"], Query, Lang) ->
_ -> _ ->
nothing nothing
end, 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))] ++ [?XC("h1", ?T("Modules at ") ++ atom_to_list(Node))] ++
case Res of case Res of
ok -> [?CT("submitted"), ?P]; ok -> [?CT("submitted"), ?P];
@ -1854,7 +1960,7 @@ get_node(Node, ["modules"], Query, Lang) ->
[node_modules_to_xhtml(NewModules, 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]), UpTime = rpc:call(Node, erlang, statistics, [wall_clock]),
UpTimeS = io_lib:format("~.3f", [element(1, UpTime)/1000]), UpTimeS = io_lib:format("~.3f", [element(1, UpTime)/1000]),
CPUTime = rpc:call(Node, erlang, statistics, [runtime]), 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")]. [?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( lists:foreach(
fun({Module, _Opts1}) -> fun({Module, _Opts1}) ->
SModule = atom_to_list(Module), SModule = atom_to_list(Module),
@ -2143,13 +2249,13 @@ node_modules_parse_query(Node, Modules, Query) ->
lists:keysearch("opts" ++ SModule, 1, Query), lists:keysearch("opts" ++ SModule, 1, Query),
{ok, Tokens, _} = erl_scan:string(SOpts ++ "."), {ok, Tokens, _} = erl_scan:string(SOpts ++ "."),
{ok, Opts} = erl_parse:parse_term(Tokens), {ok, Opts} = erl_parse:parse_term(Tokens),
rpc:call(Node, gen_mod, stop_module, [Module]), rpc:call(Node, gen_mod, stop_module, [Host, Module]),
rpc:call(Node, gen_mod, start_module, [Module, Opts]), rpc:call(Node, gen_mod, start_module, [Host, Module, Opts]),
throw(submitted); throw(submitted);
_ -> _ ->
case lists:keysearch("stop" ++ SModule, 1, Query) of case lists:keysearch("stop" ++ SModule, 1, Query) of
{value, _} -> {value, _} ->
rpc:call(Node, gen_mod, stop_module, [Module]), rpc:call(Node, gen_mod, stop_module, [Host, Module]),
throw(submitted); throw(submitted);
_ -> _ ->
ok ok
@ -2165,7 +2271,7 @@ node_modules_parse_query(Node, Modules, Query) ->
Module = list_to_atom(SModule), Module = list_to_atom(SModule),
{ok, Tokens, _} = erl_scan:string(SOpts ++ "."), {ok, Tokens, _} = erl_scan:string(SOpts ++ "."),
{ok, Opts} = erl_parse:parse_term(Tokens), {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); throw(submitted);
_ -> _ ->
ok ok