xmpp.chapril.org-ejabberd/src/ejabberd_config.erl

248 lines
6.2 KiB
Erlang

%%%----------------------------------------------------------------------
%%% File : ejabberd_config.erl
%%% Author : Alexey Shchepin <alexey@sevcom.net>
%%% Purpose : Load config file
%%% Created : 14 Dec 2002 by Alexey Shchepin <alexey@sevcom.net>
%%% Id : $Id$
%%%----------------------------------------------------------------------
-module(ejabberd_config).
-author('alexey@sevcom.net').
-vsn('$Revision$ ').
-export([start/0, load_file/1,
add_global_option/2, add_local_option/2,
get_global_option/1, get_local_option/1]).
-include("ejabberd.hrl").
-record(config, {key, value}).
-record(local_config, {key, value}).
-record(state, {opts = [],
hosts = [],
override_local = false,
override_global = false,
override_acls = false}).
start() ->
mnesia:create_table(config,
[{disc_copies, [node()]},
{attributes, record_info(fields, config)}]),
mnesia:add_table_copy(config, node(), ram_copies),
mnesia:create_table(local_config,
[{disc_copies, [node()]},
{local_content, true},
{attributes, record_info(fields, local_config)}]),
mnesia:add_table_copy(local_config, node(), ram_copies),
Config = case application:get_env(config) of
{ok, Path} -> Path;
undefined ->
case os:getenv("EJABBERD_CONFIG_PATH") of
false ->
?CONFIG_PATH;
Path ->
Path
end
end,
load_file(Config).
load_file(File) ->
case file:consult(File) of
{ok, Terms} ->
State = lists:foldl(fun search_hosts/2, #state{}, Terms),
Res = lists:foldl(fun process_term/2, State, Terms),
set_opts(Res);
{error, Reason} ->
?ERROR_MSG("Can't load config file ~p: ~p", [File, Reason]),
exit(file:format_error(Reason))
end.
search_hosts(Term, State) ->
case Term of
{host, Host} ->
if
State#state.hosts == [] ->
add_hosts_to_option([Host], State);
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_hosts_to_option(Hosts, State);
true ->
?ERROR_MSG("Can't load config file: "
"too many hosts definitions", []),
exit("too many hosts definitions")
end;
_ ->
State
end.
add_hosts_to_option(Hosts, State) ->
PrepHosts = normalize_hosts(Hosts),
add_option(hosts, PrepHosts, State#state{hosts = PrepHosts}).
normalize_hosts(Hosts) ->
normalize_hosts(Hosts,[]).
normalize_hosts([], PrepHosts) ->
lists:reverse(PrepHosts);
normalize_hosts([Host|Hosts], PrepHosts) ->
case jlib:nodeprep(Host) of
error ->
?ERROR_MSG("Can't load config file: "
"invalid host name [~p]", [Host]),
exit("invalid hostname");
PrepHost ->
normalize_hosts(Hosts, [PrepHost|PrepHosts])
end.
process_term(Term, State) ->
case Term of
override_global ->
State#state{override_global = true};
override_local ->
State#state{override_local = true};
override_acls ->
State#state{override_acls = true};
{acl, ACLName, ACLData} ->
process_host_term(Term, global, State);
{access, RuleName, Rules} ->
process_host_term(Term, global, State);
{shaper, Name, Data} ->
%lists:foldl(fun(Host, S) -> process_host_term(Term, Host, S) end,
% State, State#state.hosts);
process_host_term(Term, global, State);
{host, Host} ->
State;
{hosts, Hosts} ->
State;
{host_config, Host, Terms} ->
lists:foldl(fun(T, S) -> process_host_term(T, Host, S) end,
State, Terms);
{listen, Val} ->
add_option(listen, Val, State);
{outgoing_s2s_port, Port} ->
add_option(outgoing_s2s_port, Port, State);
{s2s_use_starttls, Port} ->
add_option(s2s_use_starttls, Port, State);
{s2s_certfile, CertFile} ->
add_option(s2s_certfile, CertFile, State);
{domain_certfile, Domain, CertFile} ->
add_option({domain_certfile, Domain}, CertFile, 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} |
State#state.opts]};
{shaper, Name, Data} ->
State#state{opts = [#config{key = {shaper, Name, Host},
value = Data} |
State#state.opts]};
{host, Host} ->
State;
{hosts, Hosts} ->
State;
{Opt, Val} ->
add_option({Opt, Host}, Val, State)
end.
add_option(Opt, Val, State) ->
Table = case Opt of
hosts ->
config;
language ->
config;
_ ->
local_config
end,
case Table of
config ->
State#state{opts = [#config{key = Opt, value = Val} |
State#state.opts]};
local_config ->
State#state{opts = [#local_config{key = Opt, value = Val} |
State#state.opts]}
end.
set_opts(State) ->
Opts = lists:reverse(State#state.opts),
F = fun() ->
if
State#state.override_global ->
Ksg = mnesia:all_keys(config),
lists:foreach(fun(K) ->
mnesia:delete({config, K})
end, Ksg);
true ->
ok
end,
if
State#state.override_local ->
Ksl = mnesia:all_keys(local_config),
lists:foreach(fun(K) ->
mnesia:delete({local_config, K})
end, Ksl);
true ->
ok
end,
if
State#state.override_acls ->
Ksa = mnesia:all_keys(acl),
lists:foreach(fun(K) ->
mnesia:delete({acl, K})
end, Ksa);
true ->
ok
end,
lists:foreach(fun(R) ->
mnesia:write(R)
end, Opts)
end,
{atomic, _} = mnesia:transaction(F).
add_global_option(Opt, Val) ->
mnesia:transaction(fun() ->
mnesia:write(#config{key = Opt,
value = Val})
end).
add_local_option(Opt, Val) ->
mnesia:transaction(fun() ->
mnesia:write(#local_config{key = Opt,
value = Val})
end).
get_global_option(Opt) ->
case ets:lookup(config, Opt) of
[#config{value = Val}] ->
Val;
_ ->
undefined
end.
get_local_option(Opt) ->
case ets:lookup(local_config, Opt) of
[#local_config{value = Val}] ->
Val;
_ ->
undefined
end.