Use a settings object for the main settings
[oweals/minetest.git] / src / script / lua_api / l_mainmenu.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 sapier
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_mainmenu.h"
21 #include "lua_api/l_internal.h"
22 #include "common/c_content.h"
23 #include "cpp_api/s_async.h"
24 #include "guiEngine.h"
25 #include "guiMainMenu.h"
26 #include "guiKeyChangeMenu.h"
27 #include "guiFileSelectMenu.h"
28 #include "subgame.h"
29 #include "version.h"
30 #include "porting.h"
31 #include "filesys.h"
32 #include "convert_json.h"
33 #include "serverlist.h"
34 #include "mapgen.h"
35 #include "settings.h"
36 #include "EDriverTypes.h"
37
38 #include <IFileArchive.h>
39 #include <IFileSystem.h>
40
41
42 /******************************************************************************/
43 std::string ModApiMainMenu::getTextData(lua_State *L, std::string name)
44 {
45         lua_getglobal(L, "gamedata");
46
47         lua_getfield(L, -1, name.c_str());
48
49         if(lua_isnil(L, -1))
50                 return "";
51
52         return luaL_checkstring(L, -1);
53 }
54
55 /******************************************************************************/
56 int ModApiMainMenu::getIntegerData(lua_State *L, std::string name,bool& valid)
57 {
58         lua_getglobal(L, "gamedata");
59
60         lua_getfield(L, -1, name.c_str());
61
62         if(lua_isnil(L, -1)) {
63                 valid = false;
64                 return -1;
65                 }
66
67         valid = true;
68         return luaL_checkinteger(L, -1);
69 }
70
71 /******************************************************************************/
72 int ModApiMainMenu::getBoolData(lua_State *L, std::string name,bool& valid)
73 {
74         lua_getglobal(L, "gamedata");
75
76         lua_getfield(L, -1, name.c_str());
77
78         if(lua_isnil(L, -1)) {
79                 valid = false;
80                 return false;
81                 }
82
83         valid = true;
84         return lua_toboolean(L, -1);
85 }
86
87 /******************************************************************************/
88 int ModApiMainMenu::l_update_formspec(lua_State *L)
89 {
90         GUIEngine* engine = getGuiEngine(L);
91         sanity_check(engine != NULL);
92
93         if (engine->m_startgame)
94                 return 0;
95
96         //read formspec
97         std::string formspec(luaL_checkstring(L, 1));
98
99         if (engine->m_formspecgui != 0) {
100                 engine->m_formspecgui->setForm(formspec);
101         }
102
103         return 0;
104 }
105
106 /******************************************************************************/
107 int ModApiMainMenu::l_start(lua_State *L)
108 {
109         GUIEngine* engine = getGuiEngine(L);
110         sanity_check(engine != NULL);
111
112         //update c++ gamedata from lua table
113
114         bool valid = false;
115
116         MainMenuData *data = engine->m_data;
117
118         data->selected_world = getIntegerData(L, "selected_world",valid) -1;
119         data->simple_singleplayer_mode = getBoolData(L,"singleplayer",valid);
120         data->do_reconnect = getBoolData(L, "do_reconnect", valid);
121         if (!data->do_reconnect) {
122                 data->name     = getTextData(L,"playername");
123                 data->password = getTextData(L,"password");
124                 data->address  = getTextData(L,"address");
125                 data->port     = getTextData(L,"port");
126         }
127         data->serverdescription = getTextData(L,"serverdescription");
128         data->servername        = getTextData(L,"servername");
129
130         //close menu next time
131         engine->m_startgame = true;
132         return 0;
133 }
134
135 /******************************************************************************/
136 int ModApiMainMenu::l_close(lua_State *L)
137 {
138         GUIEngine* engine = getGuiEngine(L);
139         sanity_check(engine != NULL);
140
141         engine->m_kill = true;
142         return 0;
143 }
144
145 /******************************************************************************/
146 int ModApiMainMenu::l_set_background(lua_State *L)
147 {
148         GUIEngine* engine = getGuiEngine(L);
149         sanity_check(engine != NULL);
150
151         std::string backgroundlevel(luaL_checkstring(L, 1));
152         std::string texturename(luaL_checkstring(L, 2));
153
154         bool tile_image = false;
155         bool retval     = false;
156         unsigned int minsize = 16;
157
158         if (!lua_isnone(L, 3)) {
159                 tile_image = lua_toboolean(L, 3);
160         }
161
162         if (!lua_isnone(L, 4)) {
163                 minsize = lua_tonumber(L, 4);
164         }
165
166         if (backgroundlevel == "background") {
167                 retval |= engine->setTexture(TEX_LAYER_BACKGROUND, texturename,
168                                 tile_image, minsize);
169         }
170
171         if (backgroundlevel == "overlay") {
172                 retval |= engine->setTexture(TEX_LAYER_OVERLAY, texturename,
173                                 tile_image, minsize);
174         }
175
176         if (backgroundlevel == "header") {
177                 retval |= engine->setTexture(TEX_LAYER_HEADER,  texturename,
178                                 tile_image, minsize);
179         }
180
181         if (backgroundlevel == "footer") {
182                 retval |= engine->setTexture(TEX_LAYER_FOOTER, texturename,
183                                 tile_image, minsize);
184         }
185
186         lua_pushboolean(L,retval);
187         return 1;
188 }
189
190 /******************************************************************************/
191 int ModApiMainMenu::l_set_clouds(lua_State *L)
192 {
193         GUIEngine* engine = getGuiEngine(L);
194         sanity_check(engine != NULL);
195
196         bool value = lua_toboolean(L,1);
197
198         engine->m_clouds_enabled = value;
199
200         return 0;
201 }
202
203 /******************************************************************************/
204 int ModApiMainMenu::l_get_textlist_index(lua_State *L)
205 {
206         // get_table_index accepts both tables and textlists
207         return l_get_table_index(L);
208 }
209
210 /******************************************************************************/
211 int ModApiMainMenu::l_get_table_index(lua_State *L)
212 {
213         GUIEngine* engine = getGuiEngine(L);
214         sanity_check(engine != NULL);
215
216         std::string tablename(luaL_checkstring(L, 1));
217         GUITable *table = engine->m_menu->getTable(tablename);
218         s32 selection = table ? table->getSelected() : 0;
219
220         if (selection >= 1)
221                 lua_pushinteger(L, selection);
222         else
223                 lua_pushnil(L);
224         return 1;
225 }
226
227 /******************************************************************************/
228 int ModApiMainMenu::l_get_worlds(lua_State *L)
229 {
230         std::vector<WorldSpec> worlds = getAvailableWorlds();
231
232         lua_newtable(L);
233         int top = lua_gettop(L);
234         unsigned int index = 1;
235
236         for (unsigned int i = 0; i < worlds.size(); i++)
237         {
238                 lua_pushnumber(L,index);
239
240                 lua_newtable(L);
241                 int top_lvl2 = lua_gettop(L);
242
243                 lua_pushstring(L,"path");
244                 lua_pushstring(L,worlds[i].path.c_str());
245                 lua_settable(L, top_lvl2);
246
247                 lua_pushstring(L,"name");
248                 lua_pushstring(L,worlds[i].name.c_str());
249                 lua_settable(L, top_lvl2);
250
251                 lua_pushstring(L,"gameid");
252                 lua_pushstring(L,worlds[i].gameid.c_str());
253                 lua_settable(L, top_lvl2);
254
255                 lua_settable(L, top);
256                 index++;
257         }
258         return 1;
259 }
260
261 /******************************************************************************/
262 int ModApiMainMenu::l_get_games(lua_State *L)
263 {
264         std::vector<SubgameSpec> games = getAvailableGames();
265
266         lua_newtable(L);
267         int top = lua_gettop(L);
268         unsigned int index = 1;
269
270         for (unsigned int i = 0; i < games.size(); i++)
271         {
272                 lua_pushnumber(L,index);
273                 lua_newtable(L);
274                 int top_lvl2 = lua_gettop(L);
275
276                 lua_pushstring(L,"id");
277                 lua_pushstring(L,games[i].id.c_str());
278                 lua_settable(L, top_lvl2);
279
280                 lua_pushstring(L,"path");
281                 lua_pushstring(L,games[i].path.c_str());
282                 lua_settable(L, top_lvl2);
283
284                 lua_pushstring(L,"gamemods_path");
285                 lua_pushstring(L,games[i].gamemods_path.c_str());
286                 lua_settable(L, top_lvl2);
287
288                 lua_pushstring(L,"name");
289                 lua_pushstring(L,games[i].name.c_str());
290                 lua_settable(L, top_lvl2);
291
292                 lua_pushstring(L,"menuicon_path");
293                 lua_pushstring(L,games[i].menuicon_path.c_str());
294                 lua_settable(L, top_lvl2);
295
296                 lua_pushstring(L,"addon_mods_paths");
297                 lua_newtable(L);
298                 int table2 = lua_gettop(L);
299                 int internal_index=1;
300                 for (std::set<std::string>::iterator iter = games[i].addon_mods_paths.begin();
301                                 iter != games[i].addon_mods_paths.end(); ++iter) {
302                         lua_pushnumber(L,internal_index);
303                         lua_pushstring(L,(*iter).c_str());
304                         lua_settable(L, table2);
305                         internal_index++;
306                 }
307                 lua_settable(L, top_lvl2);
308                 lua_settable(L, top);
309                 index++;
310         }
311         return 1;
312 }
313 /******************************************************************************/
314 int ModApiMainMenu::l_get_modstore_details(lua_State *L)
315 {
316         const char *modid       = luaL_checkstring(L, 1);
317
318         if (modid != 0) {
319                 Json::Value details;
320                 std::string url = "";
321                 try{
322                         url = g_settings->get("modstore_details_url");
323                 }
324                 catch(SettingNotFoundException &e) {
325                         lua_pushnil(L);
326                         return 1;
327                 }
328
329                 size_t idpos = url.find("*");
330                 url.erase(idpos,1);
331                 url.insert(idpos,modid);
332
333                 details = getModstoreUrl(url);
334
335                 ModStoreModDetails current_mod = readModStoreModDetails(details);
336
337                 if ( current_mod.valid) {
338                         lua_newtable(L);
339                         int top = lua_gettop(L);
340
341                         lua_pushstring(L,"id");
342                         lua_pushnumber(L,current_mod.id);
343                         lua_settable(L, top);
344
345                         lua_pushstring(L,"title");
346                         lua_pushstring(L,current_mod.title.c_str());
347                         lua_settable(L, top);
348
349                         lua_pushstring(L,"basename");
350                         lua_pushstring(L,current_mod.basename.c_str());
351                         lua_settable(L, top);
352
353                         lua_pushstring(L,"description");
354                         lua_pushstring(L,current_mod.description.c_str());
355                         lua_settable(L, top);
356
357                         lua_pushstring(L,"author");
358                         lua_pushstring(L,current_mod.author.username.c_str());
359                         lua_settable(L, top);
360
361                         lua_pushstring(L,"download_url");
362                         lua_pushstring(L,current_mod.versions[0].file.c_str());
363                         lua_settable(L, top);
364
365                         lua_pushstring(L,"versions");
366                         lua_newtable(L);
367                         int versionstop = lua_gettop(L);
368                         for (unsigned int i=0;i < current_mod.versions.size(); i++) {
369                                 lua_pushnumber(L,i+1);
370                                 lua_newtable(L);
371                                 int current_element = lua_gettop(L);
372
373                                 lua_pushstring(L,"date");
374                                 lua_pushstring(L,current_mod.versions[i].date.c_str());
375                                 lua_settable(L,current_element);
376
377                                 lua_pushstring(L,"download_url");
378                                 lua_pushstring(L,current_mod.versions[i].file.c_str());
379                                 lua_settable(L,current_element);
380
381                                 lua_settable(L,versionstop);
382                         }
383                         lua_settable(L, top);
384
385                         lua_pushstring(L,"screenshot_url");
386                         lua_pushstring(L,current_mod.titlepic.file.c_str());
387                         lua_settable(L, top);
388
389                         lua_pushstring(L,"license");
390                         lua_pushstring(L,current_mod.license.shortinfo.c_str());
391                         lua_settable(L, top);
392
393                         lua_pushstring(L,"rating");
394                         lua_pushnumber(L,current_mod.rating);
395                         lua_settable(L, top);
396
397                         //TODO depends
398
399                         //TODO softdepends
400                         return 1;
401                 }
402         }
403         return 0;
404 }
405
406 /******************************************************************************/
407 int ModApiMainMenu::l_get_modstore_list(lua_State *L)
408 {
409         Json::Value mods;
410         std::string url = "";
411         try{
412                 url = g_settings->get("modstore_listmods_url");
413         }
414         catch(SettingNotFoundException &e) {
415                 lua_pushnil(L);
416                 return 1;
417         }
418
419         mods = getModstoreUrl(url);
420
421         std::vector<ModStoreMod> moddata = readModStoreList(mods);
422
423         lua_newtable(L);
424         int top = lua_gettop(L);
425         unsigned int index = 1;
426
427         for (unsigned int i = 0; i < moddata.size(); i++)
428         {
429                 if (moddata[i].valid) {
430                         lua_pushnumber(L,index);
431                         lua_newtable(L);
432
433                         int top_lvl2 = lua_gettop(L);
434
435                         lua_pushstring(L,"id");
436                         lua_pushnumber(L,moddata[i].id);
437                         lua_settable(L, top_lvl2);
438
439                         lua_pushstring(L,"title");
440                         lua_pushstring(L,moddata[i].title.c_str());
441                         lua_settable(L, top_lvl2);
442
443                         lua_pushstring(L,"basename");
444                         lua_pushstring(L,moddata[i].basename.c_str());
445                         lua_settable(L, top_lvl2);
446
447                         lua_settable(L, top);
448                         index++;
449                 }
450         }
451         return 1;
452 }
453
454 /******************************************************************************/
455 int ModApiMainMenu::l_get_favorites(lua_State *L)
456 {
457         std::string listtype = "local";
458
459         if (!lua_isnone(L,1)) {
460                 listtype = luaL_checkstring(L,1);
461         }
462
463         std::vector<ServerListSpec> servers;
464
465         if(listtype == "online") {
466                 servers = ServerList::getOnline();
467         } else {
468                 servers = ServerList::getLocal();
469         }
470
471         lua_newtable(L);
472         int top = lua_gettop(L);
473         unsigned int index = 1;
474
475         for (unsigned int i = 0; i < servers.size(); i++)
476         {
477
478                 lua_pushnumber(L,index);
479
480                 lua_newtable(L);
481                 int top_lvl2 = lua_gettop(L);
482
483                 if (servers[i]["clients"].asString().size()) {
484                         std::string clients_raw = servers[i]["clients"].asString();
485                         char* endptr = 0;
486                         int numbervalue = strtol(clients_raw.c_str(),&endptr,10);
487
488                         if ((clients_raw != "") && (*endptr == 0)) {
489                                 lua_pushstring(L,"clients");
490                                 lua_pushnumber(L,numbervalue);
491                                 lua_settable(L, top_lvl2);
492                         }
493                 }
494
495                 if (servers[i]["clients_max"].asString().size()) {
496
497                         std::string clients_max_raw = servers[i]["clients_max"].asString();
498                         char* endptr = 0;
499                         int numbervalue = strtol(clients_max_raw.c_str(),&endptr,10);
500
501                         if ((clients_max_raw != "") && (*endptr == 0)) {
502                                 lua_pushstring(L,"clients_max");
503                                 lua_pushnumber(L,numbervalue);
504                                 lua_settable(L, top_lvl2);
505                         }
506                 }
507
508                 if (servers[i]["version"].asString().size()) {
509                         lua_pushstring(L,"version");
510                         std::string topush = servers[i]["version"].asString();
511                         lua_pushstring(L,topush.c_str());
512                         lua_settable(L, top_lvl2);
513                 }
514
515                 if (servers[i]["proto_min"].asString().size()) {
516                         lua_pushstring(L,"proto_min");
517                         lua_pushinteger(L,servers[i]["proto_min"].asInt());
518                         lua_settable(L, top_lvl2);
519                 }
520
521                 if (servers[i]["proto_max"].asString().size()) {
522                         lua_pushstring(L,"proto_max");
523                         lua_pushinteger(L,servers[i]["proto_max"].asInt());
524                         lua_settable(L, top_lvl2);
525                 }
526
527                 if (servers[i]["password"].asString().size()) {
528                         lua_pushstring(L,"password");
529                         lua_pushboolean(L,servers[i]["password"].asBool());
530                         lua_settable(L, top_lvl2);
531                 }
532
533                 if (servers[i]["creative"].asString().size()) {
534                         lua_pushstring(L,"creative");
535                         lua_pushboolean(L,servers[i]["creative"].asBool());
536                         lua_settable(L, top_lvl2);
537                 }
538
539                 if (servers[i]["damage"].asString().size()) {
540                         lua_pushstring(L,"damage");
541                         lua_pushboolean(L,servers[i]["damage"].asBool());
542                         lua_settable(L, top_lvl2);
543                 }
544
545                 if (servers[i]["pvp"].asString().size()) {
546                         lua_pushstring(L,"pvp");
547                         lua_pushboolean(L,servers[i]["pvp"].asBool());
548                         lua_settable(L, top_lvl2);
549                 }
550
551                 if (servers[i]["description"].asString().size()) {
552                         lua_pushstring(L,"description");
553                         std::string topush = servers[i]["description"].asString();
554                         lua_pushstring(L,topush.c_str());
555                         lua_settable(L, top_lvl2);
556                 }
557
558                 if (servers[i]["name"].asString().size()) {
559                         lua_pushstring(L,"name");
560                         std::string topush = servers[i]["name"].asString();
561                         lua_pushstring(L,topush.c_str());
562                         lua_settable(L, top_lvl2);
563                 }
564
565                 if (servers[i]["address"].asString().size()) {
566                         lua_pushstring(L,"address");
567                         std::string topush = servers[i]["address"].asString();
568                         lua_pushstring(L,topush.c_str());
569                         lua_settable(L, top_lvl2);
570                 }
571
572                 if (servers[i]["port"].asString().size()) {
573                         lua_pushstring(L,"port");
574                         std::string topush = servers[i]["port"].asString();
575                         lua_pushstring(L,topush.c_str());
576                         lua_settable(L, top_lvl2);
577                 }
578
579                 if (servers[i].isMember("ping")) {
580                         float ping = servers[i]["ping"].asFloat();
581                         lua_pushstring(L, "ping");
582                         lua_pushnumber(L, ping);
583                         lua_settable(L, top_lvl2);
584                 }
585
586                 lua_settable(L, top);
587                 index++;
588         }
589         return 1;
590 }
591
592 /******************************************************************************/
593 int ModApiMainMenu::l_delete_favorite(lua_State *L)
594 {
595         std::vector<ServerListSpec> servers;
596
597         std::string listtype = "local";
598
599         if (!lua_isnone(L,2)) {
600                 listtype = luaL_checkstring(L,2);
601         }
602
603         if ((listtype != "local") &&
604                 (listtype != "online"))
605                 return 0;
606
607
608         if(listtype == "online") {
609                 servers = ServerList::getOnline();
610         } else {
611                 servers = ServerList::getLocal();
612         }
613
614         int fav_idx     = luaL_checkinteger(L,1) -1;
615
616         if ((fav_idx >= 0) &&
617                         (fav_idx < (int) servers.size())) {
618
619                 ServerList::deleteEntry(servers[fav_idx]);
620         }
621
622         return 0;
623 }
624
625 /******************************************************************************/
626 int ModApiMainMenu::l_show_keys_menu(lua_State *L)
627 {
628         GUIEngine* engine = getGuiEngine(L);
629         sanity_check(engine != NULL);
630
631         GUIKeyChangeMenu *kmenu
632                 = new GUIKeyChangeMenu( engine->m_device->getGUIEnvironment(),
633                                                                 engine->m_parent,
634                                                                 -1,
635                                                                 engine->m_menumanager);
636         kmenu->drop();
637         return 0;
638 }
639
640 /******************************************************************************/
641 int ModApiMainMenu::l_create_world(lua_State *L)
642 {
643         const char *name        = luaL_checkstring(L, 1);
644         int gameidx                     = luaL_checkinteger(L,2) -1;
645
646         std::string path = porting::path_user + DIR_DELIM
647                         "worlds" + DIR_DELIM
648                         + name;
649
650         std::vector<SubgameSpec> games = getAvailableGames();
651
652         if ((gameidx >= 0) &&
653                         (gameidx < (int) games.size())) {
654
655                 // Create world if it doesn't exist
656                 if (!loadGameConfAndInitWorld(path, games[gameidx])) {
657                         lua_pushstring(L, "Failed to initialize world");
658                 } else {
659                         lua_pushnil(L);
660                 }
661         } else {
662                 lua_pushstring(L, "Invalid game index");
663         }
664         return 1;
665 }
666
667 /******************************************************************************/
668 int ModApiMainMenu::l_delete_world(lua_State *L)
669 {
670         int worldidx    = luaL_checkinteger(L,1) -1;
671
672         std::vector<WorldSpec> worlds = getAvailableWorlds();
673
674         if ((worldidx >= 0) &&
675                 (worldidx < (int) worlds.size())) {
676
677                 WorldSpec spec = worlds[worldidx];
678
679                 std::vector<std::string> paths;
680                 paths.push_back(spec.path);
681                 fs::GetRecursiveSubPaths(spec.path, paths);
682
683                 // Delete files
684                 if (!fs::DeletePaths(paths)) {
685                         lua_pushstring(L, "Failed to delete world");
686                 }
687                 else {
688                         lua_pushnil(L);
689                 }
690         }
691         else {
692                 lua_pushstring(L, "Invalid world index");
693         }
694         return 1;
695 }
696
697 /******************************************************************************/
698 int ModApiMainMenu::l_set_topleft_text(lua_State *L)
699 {
700         GUIEngine* engine = getGuiEngine(L);
701         sanity_check(engine != NULL);
702
703         std::string text = "";
704
705         if (!lua_isnone(L,1) && !lua_isnil(L,1))
706                 text = luaL_checkstring(L, 1);
707
708         engine->setTopleftText(text);
709         return 0;
710 }
711
712 /******************************************************************************/
713 int ModApiMainMenu::l_get_mapgen_names(lua_State *L)
714 {
715         std::vector<const char *> names;
716         Mapgen::getMapgenNames(&names, lua_toboolean(L, 1));
717
718         lua_newtable(L);
719         for (size_t i = 0; i != names.size(); i++) {
720                 lua_pushstring(L, names[i]);
721                 lua_rawseti(L, -2, i + 1);
722         }
723
724         return 1;
725 }
726
727
728 /******************************************************************************/
729 int ModApiMainMenu::l_get_modpath(lua_State *L)
730 {
731         std::string modpath = fs::RemoveRelativePathComponents(
732                 porting::path_user + DIR_DELIM + "mods" + DIR_DELIM);
733         lua_pushstring(L, modpath.c_str());
734         return 1;
735 }
736
737 /******************************************************************************/
738 int ModApiMainMenu::l_get_gamepath(lua_State *L)
739 {
740         std::string gamepath = fs::RemoveRelativePathComponents(
741                 porting::path_user + DIR_DELIM + "games" + DIR_DELIM);
742         lua_pushstring(L, gamepath.c_str());
743         return 1;
744 }
745
746 /******************************************************************************/
747 int ModApiMainMenu::l_get_texturepath(lua_State *L)
748 {
749         std::string gamepath = fs::RemoveRelativePathComponents(
750                 porting::path_user + DIR_DELIM + "textures");
751         lua_pushstring(L, gamepath.c_str());
752         return 1;
753 }
754
755 int ModApiMainMenu::l_get_texturepath_share(lua_State *L)
756 {
757         std::string gamepath = fs::RemoveRelativePathComponents(
758                 porting::path_share + DIR_DELIM + "textures");
759         lua_pushstring(L, gamepath.c_str());
760         return 1;
761 }
762
763 /******************************************************************************/
764 int ModApiMainMenu::l_create_dir(lua_State *L) {
765         const char *path = luaL_checkstring(L, 1);
766
767         if (ModApiMainMenu::isMinetestPath(path)) {
768                 lua_pushboolean(L, fs::CreateAllDirs(path));
769                 return 1;
770         }
771
772         lua_pushboolean(L, false);
773         return 1;
774 }
775
776 /******************************************************************************/
777 int ModApiMainMenu::l_delete_dir(lua_State *L)
778 {
779         const char *path = luaL_checkstring(L, 1);
780
781         std::string absolute_path = fs::RemoveRelativePathComponents(path);
782
783         if (ModApiMainMenu::isMinetestPath(absolute_path)) {
784                 lua_pushboolean(L, fs::RecursiveDelete(absolute_path));
785                 return 1;
786         }
787
788         lua_pushboolean(L, false);
789         return 1;
790 }
791
792 /******************************************************************************/
793 int ModApiMainMenu::l_copy_dir(lua_State *L)
794 {
795         const char *source      = luaL_checkstring(L, 1);
796         const char *destination = luaL_checkstring(L, 2);
797
798         bool keep_source = true;
799
800         if ((!lua_isnone(L,3)) &&
801                         (!lua_isnil(L,3))) {
802                 keep_source = lua_toboolean(L,3);
803         }
804
805         std::string absolute_destination = fs::RemoveRelativePathComponents(destination);
806         std::string absolute_source = fs::RemoveRelativePathComponents(source);
807
808         if ((ModApiMainMenu::isMinetestPath(absolute_source)) &&
809                         (ModApiMainMenu::isMinetestPath(absolute_destination))) {
810                 bool retval = fs::CopyDir(absolute_source,absolute_destination);
811
812                 if (retval && (!keep_source)) {
813
814                         retval &= fs::RecursiveDelete(absolute_source);
815                 }
816                 lua_pushboolean(L,retval);
817                 return 1;
818         }
819         lua_pushboolean(L,false);
820         return 1;
821 }
822
823 /******************************************************************************/
824 int ModApiMainMenu::l_extract_zip(lua_State *L)
825 {
826         GUIEngine* engine = getGuiEngine(L);
827         sanity_check(engine);
828
829         const char *zipfile     = luaL_checkstring(L, 1);
830         const char *destination = luaL_checkstring(L, 2);
831
832         std::string absolute_destination = fs::RemoveRelativePathComponents(destination);
833
834         if (ModApiMainMenu::isMinetestPath(absolute_destination)) {
835                 fs::CreateAllDirs(absolute_destination);
836
837                 io::IFileSystem* fs = engine->m_device->getFileSystem();
838
839                 if (!fs->addFileArchive(zipfile,true,false,io::EFAT_ZIP)) {
840                         lua_pushboolean(L,false);
841                         return 1;
842                 }
843
844                 sanity_check(fs->getFileArchiveCount() > 0);
845
846                 /**********************************************************************/
847                 /* WARNING this is not threadsafe!!                                   */
848                 /**********************************************************************/
849                 io::IFileArchive* opened_zip =
850                         fs->getFileArchive(fs->getFileArchiveCount()-1);
851
852                 const io::IFileList* files_in_zip = opened_zip->getFileList();
853
854                 unsigned int number_of_files = files_in_zip->getFileCount();
855
856                 for (unsigned int i=0; i < number_of_files; i++) {
857                         std::string fullpath = destination;
858                         fullpath += DIR_DELIM;
859                         fullpath += files_in_zip->getFullFileName(i).c_str();
860                         std::string fullpath_dir = fs::RemoveLastPathComponent(fullpath);
861
862                         if (!files_in_zip->isDirectory(i)) {
863                                 if (!fs::PathExists(fullpath_dir) && !fs::CreateAllDirs(fullpath_dir)) {
864                                         fs->removeFileArchive(fs->getFileArchiveCount()-1);
865                                         lua_pushboolean(L,false);
866                                         return 1;
867                                 }
868
869                                 io::IReadFile* toread = opened_zip->createAndOpenFile(i);
870
871                                 FILE *targetfile = fopen(fullpath.c_str(),"wb");
872
873                                 if (targetfile == NULL) {
874                                         fs->removeFileArchive(fs->getFileArchiveCount()-1);
875                                         lua_pushboolean(L,false);
876                                         return 1;
877                                 }
878
879                                 char read_buffer[1024];
880                                 long total_read = 0;
881
882                                 while (total_read < toread->getSize()) {
883
884                                         unsigned int bytes_read =
885                                                         toread->read(read_buffer,sizeof(read_buffer));
886                                         if ((bytes_read == 0 ) ||
887                                                 (fwrite(read_buffer, 1, bytes_read, targetfile) != bytes_read))
888                                         {
889                                                 fclose(targetfile);
890                                                 fs->removeFileArchive(fs->getFileArchiveCount()-1);
891                                                 lua_pushboolean(L,false);
892                                                 return 1;
893                                         }
894                                         total_read += bytes_read;
895                                 }
896
897                                 fclose(targetfile);
898                         }
899
900                 }
901
902                 fs->removeFileArchive(fs->getFileArchiveCount()-1);
903                 lua_pushboolean(L,true);
904                 return 1;
905         }
906
907         lua_pushboolean(L,false);
908         return 1;
909 }
910
911 /******************************************************************************/
912 int ModApiMainMenu::l_get_mainmenu_path(lua_State *L)
913 {
914         GUIEngine* engine = getGuiEngine(L);
915         sanity_check(engine != NULL);
916
917         lua_pushstring(L,engine->getScriptDir().c_str());
918         return 1;
919 }
920
921 /******************************************************************************/
922 bool ModApiMainMenu::isMinetestPath(std::string path)
923 {
924         if (fs::PathStartsWith(path,fs::TempPath()))
925                 return true;
926
927         /* games */
928         if (fs::PathStartsWith(path,fs::RemoveRelativePathComponents(porting::path_share + DIR_DELIM + "games")))
929                 return true;
930
931         /* mods */
932         if (fs::PathStartsWith(path,fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM + "mods")))
933                 return true;
934
935         /* worlds */
936         if (fs::PathStartsWith(path,fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM + "worlds")))
937                 return true;
938
939
940         return false;
941 }
942
943 /******************************************************************************/
944 int ModApiMainMenu::l_show_file_open_dialog(lua_State *L)
945 {
946         GUIEngine* engine = getGuiEngine(L);
947         sanity_check(engine != NULL);
948
949         const char *formname= luaL_checkstring(L, 1);
950         const char *title       = luaL_checkstring(L, 2);
951
952         GUIFileSelectMenu* fileOpenMenu =
953                 new GUIFileSelectMenu(engine->m_device->getGUIEnvironment(),
954                                                                 engine->m_parent,
955                                                                 -1,
956                                                                 engine->m_menumanager,
957                                                                 title,
958                                                                 formname);
959         fileOpenMenu->setTextDest(engine->m_buttonhandler);
960         fileOpenMenu->drop();
961         return 0;
962 }
963
964 /******************************************************************************/
965 int ModApiMainMenu::l_download_file(lua_State *L)
966 {
967         const char *url    = luaL_checkstring(L, 1);
968         const char *target = luaL_checkstring(L, 2);
969
970         //check path
971         std::string absolute_destination = fs::RemoveRelativePathComponents(target);
972
973         if (ModApiMainMenu::isMinetestPath(absolute_destination)) {
974                 if (GUIEngine::downloadFile(url,absolute_destination)) {
975                         lua_pushboolean(L,true);
976                         return 1;
977                 }
978         } else {
979                 errorstream << "DOWNLOAD denied: " << absolute_destination
980                                 << " isn't a allowed path" << std::endl;
981         }
982         lua_pushboolean(L,false);
983         return 1;
984 }
985
986 /******************************************************************************/
987 int ModApiMainMenu::l_get_video_drivers(lua_State *L)
988 {
989         std::vector<irr::video::E_DRIVER_TYPE> drivers
990                 = porting::getSupportedVideoDrivers();
991
992         lua_newtable(L);
993         for (u32 i = 0; i != drivers.size(); i++) {
994                 const char *name  = porting::getVideoDriverName(drivers[i]);
995                 const char *fname = porting::getVideoDriverFriendlyName(drivers[i]);
996
997                 lua_newtable(L);
998                 lua_pushstring(L, name);
999                 lua_setfield(L, -2, "name");
1000                 lua_pushstring(L, fname);
1001                 lua_setfield(L, -2, "friendly_name");
1002
1003                 lua_rawseti(L, -2, i + 1);
1004         }
1005
1006         return 1;
1007 }
1008
1009 /******************************************************************************/
1010 int ModApiMainMenu::l_get_video_modes(lua_State *L)
1011 {
1012         std::vector<core::vector3d<u32> > videomodes
1013                 = porting::getSupportedVideoModes();
1014
1015         lua_newtable(L);
1016         for (u32 i = 0; i != videomodes.size(); i++) {
1017                 lua_newtable(L);
1018                 lua_pushnumber(L, videomodes[i].X);
1019                 lua_setfield(L, -2, "w");
1020                 lua_pushnumber(L, videomodes[i].Y);
1021                 lua_setfield(L, -2, "h");
1022                 lua_pushnumber(L, videomodes[i].Z);
1023                 lua_setfield(L, -2, "depth");
1024
1025                 lua_rawseti(L, -2, i + 1);
1026         }
1027
1028         return 1;
1029 }
1030
1031 /******************************************************************************/
1032 int ModApiMainMenu::l_gettext(lua_State *L)
1033 {
1034         std::string text = strgettext(std::string(luaL_checkstring(L, 1)));
1035         lua_pushstring(L, text.c_str());
1036
1037         return 1;
1038 }
1039
1040 /******************************************************************************/
1041 int ModApiMainMenu::l_get_screen_info(lua_State *L)
1042 {
1043         lua_newtable(L);
1044         int top = lua_gettop(L);
1045         lua_pushstring(L,"density");
1046         lua_pushnumber(L,porting::getDisplayDensity());
1047         lua_settable(L, top);
1048
1049         lua_pushstring(L,"display_width");
1050         lua_pushnumber(L,porting::getDisplaySize().X);
1051         lua_settable(L, top);
1052
1053         lua_pushstring(L,"display_height");
1054         lua_pushnumber(L,porting::getDisplaySize().Y);
1055         lua_settable(L, top);
1056
1057         lua_pushstring(L,"window_width");
1058         lua_pushnumber(L,porting::getWindowSize().X);
1059         lua_settable(L, top);
1060
1061         lua_pushstring(L,"window_height");
1062         lua_pushnumber(L,porting::getWindowSize().Y);
1063         lua_settable(L, top);
1064         return 1;
1065 }
1066
1067 /******************************************************************************/
1068 int ModApiMainMenu::l_get_min_supp_proto(lua_State *L)
1069 {
1070         u16 proto_version_min = g_settings->getFlag("send_pre_v25_init") ?
1071                 CLIENT_PROTOCOL_VERSION_MIN_LEGACY : CLIENT_PROTOCOL_VERSION_MIN;
1072         lua_pushinteger(L, proto_version_min);
1073         return 1;
1074 }
1075
1076 int ModApiMainMenu::l_get_max_supp_proto(lua_State *L)
1077 {
1078         lua_pushinteger(L, CLIENT_PROTOCOL_VERSION_MAX);
1079         return 1;
1080 }
1081
1082 /******************************************************************************/
1083 int ModApiMainMenu::l_do_async_callback(lua_State *L)
1084 {
1085         GUIEngine* engine = getGuiEngine(L);
1086
1087         size_t func_length, param_length;
1088         const char* serialized_func_raw = luaL_checklstring(L, 1, &func_length);
1089
1090         const char* serialized_param_raw = luaL_checklstring(L, 2, &param_length);
1091
1092         sanity_check(serialized_func_raw != NULL);
1093         sanity_check(serialized_param_raw != NULL);
1094
1095         std::string serialized_func = std::string(serialized_func_raw, func_length);
1096         std::string serialized_param = std::string(serialized_param_raw, param_length);
1097
1098         lua_pushinteger(L, engine->queueAsync(serialized_func, serialized_param));
1099
1100         return 1;
1101 }
1102
1103 /******************************************************************************/
1104 void ModApiMainMenu::Initialize(lua_State *L, int top)
1105 {
1106         API_FCT(update_formspec);
1107         API_FCT(set_clouds);
1108         API_FCT(get_textlist_index);
1109         API_FCT(get_table_index);
1110         API_FCT(get_worlds);
1111         API_FCT(get_games);
1112         API_FCT(start);
1113         API_FCT(close);
1114         API_FCT(get_favorites);
1115         API_FCT(show_keys_menu);
1116         API_FCT(create_world);
1117         API_FCT(delete_world);
1118         API_FCT(delete_favorite);
1119         API_FCT(set_background);
1120         API_FCT(set_topleft_text);
1121         API_FCT(get_mapgen_names);
1122         API_FCT(get_modpath);
1123         API_FCT(get_gamepath);
1124         API_FCT(get_texturepath);
1125         API_FCT(get_texturepath_share);
1126         API_FCT(create_dir);
1127         API_FCT(delete_dir);
1128         API_FCT(copy_dir);
1129         API_FCT(extract_zip);
1130         API_FCT(get_mainmenu_path);
1131         API_FCT(show_file_open_dialog);
1132         API_FCT(download_file);
1133         API_FCT(get_modstore_details);
1134         API_FCT(get_modstore_list);
1135         API_FCT(gettext);
1136         API_FCT(get_video_drivers);
1137         API_FCT(get_video_modes);
1138         API_FCT(get_screen_info);
1139         API_FCT(get_min_supp_proto);
1140         API_FCT(get_max_supp_proto);
1141         API_FCT(do_async_callback);
1142 }
1143
1144 /******************************************************************************/
1145 void ModApiMainMenu::InitializeAsync(lua_State *L, int top)
1146 {
1147
1148         API_FCT(get_worlds);
1149         API_FCT(get_games);
1150         API_FCT(get_favorites);
1151         API_FCT(get_mapgen_names);
1152         API_FCT(get_modpath);
1153         API_FCT(get_gamepath);
1154         API_FCT(get_texturepath);
1155         API_FCT(get_texturepath_share);
1156         API_FCT(create_dir);
1157         API_FCT(delete_dir);
1158         API_FCT(copy_dir);
1159         //API_FCT(extract_zip); //TODO remove dependency to GuiEngine
1160         API_FCT(download_file);
1161         API_FCT(get_modstore_details);
1162         API_FCT(get_modstore_list);
1163         //API_FCT(gettext); (gettext lib isn't threadsafe)
1164 }
1165