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