a50e7223c442de42aa3e42d4b9606a3d4bdef54d
[prosody.git] / core / configmanager.lua
1 -- Prosody IM v0.2
2 -- Copyright (C) 2008 Matthew Wild
3 -- Copyright (C) 2008 Waqas Hussain
4 -- 
5 -- This program is free software; you can redistribute it and/or
6 -- modify it under the terms of the GNU General Public License
7 -- as published by the Free Software Foundation; either version 2
8 -- of the License, or (at your option) any later version.
9 -- 
10 -- This program is distributed in the hope that it will be useful,
11 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
12 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 -- GNU General Public License for more details.
14 -- 
15 -- You should have received a copy of the GNU General Public License
16 -- along with this program; if not, write to the Free Software
17 -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 --
19
20
21
22 local _G = _G;
23 local   setmetatable, loadfile, pcall, rawget, rawset, io = 
24                 setmetatable, loadfile, pcall, rawget, rawset, io;
25
26 module "configmanager"
27
28 local parsers = {};
29
30 local config = { ["*"] = { core = {} } };
31
32 local global_config = config["*"];
33
34 -- When host not found, use global
35 setmetatable(config, { __index = function () return global_config; end});
36 local host_mt = { __index = global_config };
37
38 -- When key not found in section, check key in global's section
39 function section_mt(section_name)
40         return { __index =      function (t, k)
41                                                                         local section = rawget(global_config, section_name);
42                                                                         if not section then return nil; end
43                                                                         return section[k];
44                                                         end };
45 end
46
47 function getconfig()
48         return config;
49 end
50
51 function get(host, section, key)
52         local sec = config[host][section];
53         if sec then
54                 return sec[key];
55         end
56         return nil;
57 end
58
59 function set(host, section, key, value)
60         if host and section and key then
61                 local hostconfig = rawget(config, host);
62                 if not hostconfig then
63                         hostconfig = rawset(config, host, setmetatable({}, host_mt))[host];
64                 end
65                 if not rawget(hostconfig, section) then
66                         hostconfig[section] = setmetatable({}, section_mt(section));
67                 end
68                 hostconfig[section][key] = value;
69                 return true;
70         end
71         return false;
72 end
73
74 function load(filename, format)
75         format = format or filename:match("%w+$");
76
77         if parsers[format] and parsers[format].load then
78                 local f, err = io.open(filename);
79                 if f then 
80                         local ok, err = parsers[format].load(f:read("*a"));
81                         f:close();
82                         return ok, err;
83                 end
84                 return f, err;
85         end
86
87         if not format then
88                 return nil, "no parser specified";
89         else
90                 return nil, "no parser for "..(format);
91         end
92 end
93
94 function save(filename, format)
95 end
96
97 function addparser(format, parser)
98         if format and parser then
99                 parsers[format] = parser;
100         end
101 end
102
103 -- Built-in Lua parser
104 do
105         local loadstring, pcall, setmetatable = _G.loadstring, _G.pcall, _G.setmetatable;
106         local setfenv, rawget, tostring = _G.setfenv, _G.rawget, _G.tostring;
107         parsers.lua = {};
108         function parsers.lua.load(data)
109                 local env;
110                 -- The ' = true' are needed so as not to set off __newindex when we assign the functions below
111                 env = setmetatable({ Host = true; host = true; Component = true, component = true }, { __index = function (t, k)
112                                                                                                 return rawget(_G, k) or
113                                                                                                                 function (settings_table)
114                                                                                                                         config[__currenthost or "*"][k] = settings_table;
115                                                                                                                 end;
116                                                                                 end,
117                                                                 __newindex = function (t, k, v)
118                                                                                         set(env.__currenthost or "*", "core", k, v);
119                                                                                 end});
120                 
121                 function env.Host(name)
122                         rawset(env, "__currenthost", name);
123                         -- Needs at least one setting to logically exist :)
124                         set(name or "*", "core", "defined", true);
125                 end
126                 env.host = env.Host;
127                 
128                 function env.Component(name)
129                         return function (module)
130                                         set(name, "core", "component_module", module);
131                                         -- Don't load the global modules by default
132                                         set(name, "core", "modules_enable", false);
133                                         rawset(env, "__currenthost", name);
134                                 end
135                 end
136                 env.component = env.Component;
137                 
138                 local chunk, err = loadstring(data);
139                 
140                 if not chunk then
141                         return nil, err;
142                 end
143                 
144                 setfenv(chunk, env);
145                 
146                 local ok, err = pcall(chunk);
147                 
148                 if not ok then
149                         return nil, err;
150                 end
151                 
152                 return true;
153         end
154         
155 end
156
157 return _M;