Fix for never checking if the first module for a host is already loaded (affects...
[prosody.git] / core / configmanager.lua
1 -- Prosody IM v0.3
2 -- Copyright (C) 2008-2009 Matthew Wild
3 -- Copyright (C) 2008-2009 Waqas Hussain
4 -- 
5 -- This project is MIT/X11 licensed. Please see the
6 -- COPYING file in the source package for more information.
7 --
8
9
10
11 local _G = _G;
12 local   setmetatable, loadfile, pcall, rawget, rawset, io = 
13                 setmetatable, loadfile, pcall, rawget, rawset, io;
14
15 module "configmanager"
16
17 local parsers = {};
18
19 local config = { ["*"] = { core = {} } };
20
21 local global_config = config["*"];
22
23 -- When host not found, use global
24 setmetatable(config, { __index = function () return global_config; end});
25 local host_mt = { __index = global_config };
26
27 -- When key not found in section, check key in global's section
28 function section_mt(section_name)
29         return { __index =      function (t, k)
30                                                                         local section = rawget(global_config, section_name);
31                                                                         if not section then return nil; end
32                                                                         return section[k];
33                                                         end };
34 end
35
36 function getconfig()
37         return config;
38 end
39
40 function get(host, section, key)
41         local sec = config[host][section];
42         if sec then
43                 return sec[key];
44         end
45         return nil;
46 end
47
48 function set(host, section, key, value)
49         if host and section and key then
50                 local hostconfig = rawget(config, host);
51                 if not hostconfig then
52                         hostconfig = rawset(config, host, setmetatable({}, host_mt))[host];
53                 end
54                 if not rawget(hostconfig, section) then
55                         hostconfig[section] = setmetatable({}, section_mt(section));
56                 end
57                 hostconfig[section][key] = value;
58                 return true;
59         end
60         return false;
61 end
62
63 function load(filename, format)
64         format = format or filename:match("%w+$");
65
66         if parsers[format] and parsers[format].load then
67                 local f, err = io.open(filename);
68                 if f then 
69                         local ok, err = parsers[format].load(f:read("*a"));
70                         f:close();
71                         return ok, err;
72                 end
73                 return f, err;
74         end
75
76         if not format then
77                 return nil, "no parser specified";
78         else
79                 return nil, "no parser for "..(format);
80         end
81 end
82
83 function save(filename, format)
84 end
85
86 function addparser(format, parser)
87         if format and parser then
88                 parsers[format] = parser;
89         end
90 end
91
92 -- Built-in Lua parser
93 do
94         local loadstring, pcall, setmetatable = _G.loadstring, _G.pcall, _G.setmetatable;
95         local setfenv, rawget, tostring = _G.setfenv, _G.rawget, _G.tostring;
96         parsers.lua = {};
97         function parsers.lua.load(data)
98                 local env;
99                 -- The ' = true' are needed so as not to set off __newindex when we assign the functions below
100                 env = setmetatable({ Host = true; host = true; Component = true, component = true }, { __index = function (t, k)
101                                                                                                 return rawget(_G, k) or
102                                                                                                                 function (settings_table)
103                                                                                                                         config[__currenthost or "*"][k] = settings_table;
104                                                                                                                 end;
105                                                                                 end,
106                                                                 __newindex = function (t, k, v)
107                                                                                         set(env.__currenthost or "*", "core", k, v);
108                                                                                 end});
109                 
110                 function env.Host(name)
111                         rawset(env, "__currenthost", name);
112                         -- Needs at least one setting to logically exist :)
113                         set(name or "*", "core", "defined", true);
114                 end
115                 env.host = env.Host;
116                 
117                 function env.Component(name)
118                         return function (module)
119                                         set(name, "core", "component_module", module);
120                                         -- Don't load the global modules by default
121                                         set(name, "core", "modules_enable", false);
122                                         rawset(env, "__currenthost", name);
123                                 end
124                 end
125                 env.component = env.Component;
126                 
127                 local chunk, err = loadstring(data);
128                 
129                 if not chunk then
130                         return nil, err;
131                 end
132                 
133                 setfenv(chunk, env);
134                 
135                 local ok, err = pcall(chunk);
136                 
137                 if not ok then
138                         return nil, err;
139                 end
140                 
141                 return true;
142         end
143         
144 end
145
146 return _M;