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