]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/lua_api/l_util.cpp
Add AreaStore data structure
[dragonfireclient.git] / src / script / lua_api / l_util.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (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 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "lua_api/l_util.h"
21 #include "lua_api/l_internal.h"
22 #include "common/c_converter.h"
23 #include "common/c_content.h"
24 #include "cpp_api/s_async.h"
25 #include "serialization.h"
26 #include "json/json.h"
27 #include "cpp_api/s_security.h"
28 #include "areastore.h"
29 #include "debug.h"
30 #include "porting.h"
31 #include "log.h"
32 #include "tool.h"
33 #include "filesys.h"
34 #include "settings.h"
35 #include "util/auth.h"
36 #include <algorithm>
37
38 // debug(...)
39 // Writes a line to dstream
40 int ModApiUtil::l_debug(lua_State *L)
41 {
42         NO_MAP_LOCK_REQUIRED;
43         // Handle multiple parameters to behave like standard lua print()
44         int n = lua_gettop(L);
45         lua_getglobal(L, "tostring");
46         for (int i = 1; i <= n; i++) {
47                 /*
48                         Call tostring(i-th argument).
49                         This is what print() does, and it behaves a bit
50                         differently from directly calling lua_tostring.
51                 */
52                 lua_pushvalue(L, -1);  /* function to be called */
53                 lua_pushvalue(L, i);   /* value to print */
54                 lua_call(L, 1, 1);
55                 size_t len;
56                 const char *s = lua_tolstring(L, -1, &len);
57                 if (i > 1)
58                         dstream << "\t";
59                 if (s)
60                         dstream << std::string(s, len);
61                 lua_pop(L, 1);
62         }
63         dstream << std::endl;
64         return 0;
65 }
66
67 // log([level,] text)
68 // Writes a line to the logger.
69 // The one-argument version logs to infostream.
70 // The two-argument version accept a log level: error, action, info, or verbose.
71 int ModApiUtil::l_log(lua_State *L)
72 {
73         NO_MAP_LOCK_REQUIRED;
74         std::string text;
75         LogMessageLevel level = LMT_INFO;
76         if (lua_isnone(L, 2)) {
77                 text = lua_tostring(L, 1);
78         }
79         else {
80                 std::string levelname = luaL_checkstring(L, 1);
81                 text = luaL_checkstring(L, 2);
82                 if(levelname == "error")
83                         level = LMT_ERROR;
84                 else if(levelname == "action")
85                         level = LMT_ACTION;
86                 else if(levelname == "verbose")
87                         level = LMT_VERBOSE;
88                 else if (levelname == "deprecated") {
89                         log_deprecated(L,text);
90                         return 0;
91                 }
92
93         }
94         log_printline(level, text);
95         return 0;
96 }
97
98 #define CHECK_SECURE_SETTING(L, name) \
99         if (name.compare(0, 7, "secure.") == 0) {\
100                 lua_pushliteral(L, "Attempt to set secure setting.");\
101                 lua_error(L);\
102         }
103
104 // setting_set(name, value)
105 int ModApiUtil::l_setting_set(lua_State *L)
106 {
107         NO_MAP_LOCK_REQUIRED;
108         std::string name = luaL_checkstring(L, 1);
109         std::string value = luaL_checkstring(L, 2);
110         CHECK_SECURE_SETTING(L, name);
111         g_settings->set(name, value);
112         return 0;
113 }
114
115 // setting_get(name)
116 int ModApiUtil::l_setting_get(lua_State *L)
117 {
118         NO_MAP_LOCK_REQUIRED;
119         const char *name = luaL_checkstring(L, 1);
120         try{
121                 std::string value = g_settings->get(name);
122                 lua_pushstring(L, value.c_str());
123         } catch(SettingNotFoundException &e){
124                 lua_pushnil(L);
125         }
126         return 1;
127 }
128
129 // setting_setbool(name)
130 int ModApiUtil::l_setting_setbool(lua_State *L)
131 {
132         NO_MAP_LOCK_REQUIRED;
133         std::string name = luaL_checkstring(L, 1);
134         bool value = lua_toboolean(L, 2);
135         CHECK_SECURE_SETTING(L, name);
136         g_settings->setBool(name, value);
137         return 0;
138 }
139
140 // setting_getbool(name)
141 int ModApiUtil::l_setting_getbool(lua_State *L)
142 {
143         NO_MAP_LOCK_REQUIRED;
144         const char *name = luaL_checkstring(L, 1);
145         try{
146                 bool value = g_settings->getBool(name);
147                 lua_pushboolean(L, value);
148         } catch(SettingNotFoundException &e){
149                 lua_pushnil(L);
150         }
151         return 1;
152 }
153
154 // setting_save()
155 int ModApiUtil::l_setting_save(lua_State *L)
156 {
157         NO_MAP_LOCK_REQUIRED;
158         if(g_settings_path != "")
159                 g_settings->updateConfigFile(g_settings_path.c_str());
160         return 0;
161 }
162
163 // parse_json(str[, nullvalue])
164 int ModApiUtil::l_parse_json(lua_State *L)
165 {
166         NO_MAP_LOCK_REQUIRED;
167
168         const char *jsonstr = luaL_checkstring(L, 1);
169
170         // Use passed nullvalue or default to nil
171         int nullindex = 2;
172         if (lua_isnone(L, nullindex)) {
173                 lua_pushnil(L);
174                 nullindex = lua_gettop(L);
175         }
176
177         Json::Value root;
178
179         {
180                 Json::Reader reader;
181                 std::istringstream stream(jsonstr);
182
183                 if (!reader.parse(stream, root)) {
184                         errorstream << "Failed to parse json data "
185                                 << reader.getFormattedErrorMessages();
186                         errorstream << "data: \"" << jsonstr << "\""
187                                 << std::endl;
188                         lua_pushnil(L);
189                         return 1;
190                 }
191         }
192
193         if (!push_json_value(L, root, nullindex)) {
194                 errorstream << "Failed to parse json data, "
195                         << "depth exceeds lua stack limit" << std::endl;
196                 errorstream << "data: \"" << jsonstr << "\"" << std::endl;
197                 lua_pushnil(L);
198         }
199         return 1;
200 }
201
202 // write_json(data[, styled]) -> string or nil and error message
203 int ModApiUtil::l_write_json(lua_State *L)
204 {
205         NO_MAP_LOCK_REQUIRED;
206
207         bool styled = false;
208         if (!lua_isnone(L, 2)) {
209                 styled = lua_toboolean(L, 2);
210                 lua_pop(L, 1);
211         }
212
213         Json::Value root;
214         try {
215                 read_json_value(L, root, 1);
216         } catch (SerializationError &e) {
217                 lua_pushnil(L);
218                 lua_pushstring(L, e.what());
219                 return 2;
220         }
221
222         std::string out;
223         if (styled) {
224                 Json::StyledWriter writer;
225                 out = writer.write(root);
226         } else {
227                 Json::FastWriter writer;
228                 out = writer.write(root);
229         }
230         lua_pushlstring(L, out.c_str(), out.size());
231         return 1;
232 }
233
234 // get_dig_params(groups, tool_capabilities[, time_from_last_punch])
235 int ModApiUtil::l_get_dig_params(lua_State *L)
236 {
237         NO_MAP_LOCK_REQUIRED;
238         std::map<std::string, int> groups;
239         read_groups(L, 1, groups);
240         ToolCapabilities tp = read_tool_capabilities(L, 2);
241         if(lua_isnoneornil(L, 3))
242                 push_dig_params(L, getDigParams(groups, &tp));
243         else
244                 push_dig_params(L, getDigParams(groups, &tp,
245                                         luaL_checknumber(L, 3)));
246         return 1;
247 }
248
249 // get_hit_params(groups, tool_capabilities[, time_from_last_punch])
250 int ModApiUtil::l_get_hit_params(lua_State *L)
251 {
252         NO_MAP_LOCK_REQUIRED;
253         std::map<std::string, int> groups;
254         read_groups(L, 1, groups);
255         ToolCapabilities tp = read_tool_capabilities(L, 2);
256         if(lua_isnoneornil(L, 3))
257                 push_hit_params(L, getHitParams(groups, &tp));
258         else
259                 push_hit_params(L, getHitParams(groups, &tp,
260                                         luaL_checknumber(L, 3)));
261         return 1;
262 }
263
264 // get_password_hash(name, raw_password)
265 int ModApiUtil::l_get_password_hash(lua_State *L)
266 {
267         NO_MAP_LOCK_REQUIRED;
268         std::string name = luaL_checkstring(L, 1);
269         std::string raw_password = luaL_checkstring(L, 2);
270         std::string hash = translatePassword(name, raw_password);
271         lua_pushstring(L, hash.c_str());
272         return 1;
273 }
274
275 // is_yes(arg)
276 int ModApiUtil::l_is_yes(lua_State *L)
277 {
278         NO_MAP_LOCK_REQUIRED;
279
280         lua_getglobal(L, "tostring"); // function to be called
281         lua_pushvalue(L, 1); // 1st argument
282         lua_call(L, 1, 1); // execute function
283         std::string str(lua_tostring(L, -1)); // get result
284         lua_pop(L, 1);
285
286         bool yes = is_yes(str);
287         lua_pushboolean(L, yes);
288         return 1;
289 }
290
291 int ModApiUtil::l_get_builtin_path(lua_State *L)
292 {
293         std::string path = porting::path_share + DIR_DELIM + "builtin";
294         lua_pushstring(L, path.c_str());
295         return 1;
296 }
297
298 // compress(data, method, level)
299 int ModApiUtil::l_compress(lua_State *L)
300 {
301         size_t size;
302         const char *data = luaL_checklstring(L, 1, &size);
303
304         int level = -1;
305         if (!lua_isnone(L, 3) && !lua_isnil(L, 3))
306                 level = luaL_checknumber(L, 3);
307
308         std::ostringstream os;
309         compressZlib(std::string(data, size), os, level);
310
311         std::string out = os.str();
312
313         lua_pushlstring(L, out.data(), out.size());
314         return 1;
315 }
316
317 // decompress(data, method)
318 int ModApiUtil::l_decompress(lua_State *L)
319 {
320         size_t size;
321         const char *data = luaL_checklstring(L, 1, &size);
322
323         std::istringstream is(std::string(data, size));
324         std::ostringstream os;
325         decompressZlib(is, os);
326
327         std::string out = os.str();
328
329         lua_pushlstring(L, out.data(), out.size());
330         return 1;
331 }
332
333 // mkdir(path)
334 int ModApiUtil::l_mkdir(lua_State *L)
335 {
336         NO_MAP_LOCK_REQUIRED;
337         const char *path = luaL_checkstring(L, 1);
338         CHECK_SECURE_PATH_OPTIONAL(L, path);
339         lua_pushboolean(L, fs::CreateAllDirs(path));
340         return 1;
341 }
342
343 // get_dir_list(path, is_dir)
344 int ModApiUtil::l_get_dir_list(lua_State *L)
345 {
346         NO_MAP_LOCK_REQUIRED;
347         const char *path = luaL_checkstring(L, 1);
348         short is_dir = lua_isboolean(L, 2) ? lua_toboolean(L, 2) : -1;
349
350         CHECK_SECURE_PATH_OPTIONAL(L, path);
351
352         std::vector<fs::DirListNode> list = fs::GetDirListing(path);
353
354         int index = 0;
355         lua_newtable(L);
356
357         for (size_t i = 0; i < list.size(); i++) {
358                 if (is_dir == -1 || is_dir == list[i].dir) {
359                         lua_pushstring(L, list[i].name.c_str());
360                         lua_rawseti(L, -2, ++index);
361                 }
362         }
363
364         return 1;
365 }
366
367 int ModApiUtil::l_request_insecure_environment(lua_State *L)
368 {
369         NO_MAP_LOCK_REQUIRED;
370         if (!ScriptApiSecurity::isSecure(L)) {
371                 lua_getglobal(L, "_G");
372                 return 1;
373         }
374         lua_getfield(L, LUA_REGISTRYINDEX, SCRIPT_MOD_NAME_FIELD);
375         if (!lua_isstring(L, -1)) {
376                 lua_pushnil(L);
377                 return 1;
378         }
379         const char *mod_name = lua_tostring(L, -1);
380         std::string trusted_mods = g_settings->get("secure.trusted_mods");
381         std::vector<std::string> mod_list = str_split(trusted_mods, ',');
382         if (std::find(mod_list.begin(), mod_list.end(), mod_name) == mod_list.end()) {
383                 lua_pushnil(L);
384                 return 1;
385         }
386         lua_getfield(L, LUA_REGISTRYINDEX, "globals_backup");
387         return 1;
388 }
389
390
391 void ModApiUtil::Initialize(lua_State *L, int top)
392 {
393         API_FCT(debug);
394         API_FCT(log);
395
396         API_FCT(setting_set);
397         API_FCT(setting_get);
398         API_FCT(setting_setbool);
399         API_FCT(setting_getbool);
400         API_FCT(setting_save);
401
402         API_FCT(parse_json);
403         API_FCT(write_json);
404
405         API_FCT(get_dig_params);
406         API_FCT(get_hit_params);
407
408         API_FCT(get_password_hash);
409
410         API_FCT(is_yes);
411
412         API_FCT(get_builtin_path);
413
414         API_FCT(compress);
415         API_FCT(decompress);
416
417         API_FCT(mkdir);
418         API_FCT(get_dir_list);
419
420         API_FCT(request_insecure_environment);
421 }
422
423 void ModApiUtil::InitializeAsync(AsyncEngine& engine)
424 {
425         ASYNC_API_FCT(debug);
426         ASYNC_API_FCT(log);
427
428         //ASYNC_API_FCT(setting_set);
429         ASYNC_API_FCT(setting_get);
430         //ASYNC_API_FCT(setting_setbool);
431         ASYNC_API_FCT(setting_getbool);
432         //ASYNC_API_FCT(setting_save);
433
434         ASYNC_API_FCT(parse_json);
435         ASYNC_API_FCT(write_json);
436
437         ASYNC_API_FCT(is_yes);
438
439         ASYNC_API_FCT(get_builtin_path);
440
441         ASYNC_API_FCT(compress);
442         ASYNC_API_FCT(decompress);
443
444         ASYNC_API_FCT(mkdir);
445         ASYNC_API_FCT(get_dir_list);
446 }
447