]> git.lizzy.rs Git - minetest.git/blob - src/guiLuaApi.cpp
Use hexadecimal RRGGBB instead of colorkeys, rename getColor to parseColor
[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
207         //close menu next time
208         engine->m_startgame = true;
209         return 0;
210 }
211
212 /******************************************************************************/
213 int guiLuaApi::l_close(lua_State *L)
214 {
215         GUIEngine* engine = get_engine(L);
216         assert(engine != 0);
217
218         engine->m_data->kill = true;
219
220         //close menu next time
221         engine->m_startgame = true;
222         engine->m_menu->quitMenu();
223         return 0;
224 }
225
226 /******************************************************************************/
227 int guiLuaApi::l_set_background(lua_State *L)
228 {
229         GUIEngine* engine = get_engine(L);
230         assert(engine != 0);
231
232         std::string backgroundlevel(luaL_checkstring(L, 1));
233         std::string texturename(luaL_checkstring(L, 2));
234
235         bool retval = false;
236
237         if (backgroundlevel == "background") {
238                 retval |= engine->setTexture(TEX_LAYER_BACKGROUND,texturename);
239         }
240
241         if (backgroundlevel == "overlay") {
242                 retval |= engine->setTexture(TEX_LAYER_OVERLAY,texturename);
243         }
244
245         if (backgroundlevel == "header") {
246                 retval |= engine->setTexture(TEX_LAYER_HEADER,texturename);
247         }
248
249         if (backgroundlevel == "footer") {
250                 retval |= engine->setTexture(TEX_LAYER_FOOTER,texturename);
251         }
252
253         lua_pushboolean(L,retval);
254         return 1;
255 }
256
257 /******************************************************************************/
258 int guiLuaApi::l_set_clouds(lua_State *L)
259 {
260         GUIEngine* engine = get_engine(L);
261         assert(engine != 0);
262
263         bool value = lua_toboolean(L,1);
264
265         engine->m_clouds_enabled = value;
266
267         return 0;
268 }
269
270 /******************************************************************************/
271 int guiLuaApi::l_get_textlist_index(lua_State *L)
272 {
273         GUIEngine* engine = get_engine(L);
274         assert(engine != 0);
275
276         std::string listboxname(luaL_checkstring(L, 1));
277
278         int selection = engine->m_menu->getListboxIndex(listboxname);
279
280         if (selection >= 0)
281                 selection++;
282
283         lua_pushinteger(L, selection);
284         return 1;
285 }
286
287 /******************************************************************************/
288 int guiLuaApi::l_get_worlds(lua_State *L)
289 {
290         GUIEngine* engine = get_engine(L);
291         assert(engine != 0);
292
293         std::vector<WorldSpec> worlds = getAvailableWorlds();
294
295         lua_newtable(L);
296         int top = lua_gettop(L);
297         unsigned int index = 1;
298
299         for (unsigned int i = 0; i < worlds.size(); i++)
300         {
301                 lua_pushnumber(L,index);
302
303                 lua_newtable(L);
304                 int top_lvl2 = lua_gettop(L);
305
306                 lua_pushstring(L,"path");
307                 lua_pushstring(L,worlds[i].path.c_str());
308                 lua_settable(L, top_lvl2);
309
310                 lua_pushstring(L,"name");
311                 lua_pushstring(L,worlds[i].name.c_str());
312                 lua_settable(L, top_lvl2);
313
314                 lua_pushstring(L,"gameid");
315                 lua_pushstring(L,worlds[i].gameid.c_str());
316                 lua_settable(L, top_lvl2);
317
318                 lua_settable(L, top);
319                 index++;
320         }
321         return 1;
322 }
323
324 /******************************************************************************/
325 int guiLuaApi::l_get_games(lua_State *L)
326 {
327         GUIEngine* engine = get_engine(L);
328         assert(engine != 0);
329
330         std::vector<SubgameSpec> games = getAvailableGames();
331
332         lua_newtable(L);
333         int top = lua_gettop(L);
334         unsigned int index = 1;
335
336         for (unsigned int i = 0; i < games.size(); i++)
337         {
338                 lua_pushnumber(L,index);
339                 lua_newtable(L);
340                 int top_lvl2 = lua_gettop(L);
341
342                 lua_pushstring(L,"id");
343                 lua_pushstring(L,games[i].id.c_str());
344                 lua_settable(L, top_lvl2);
345
346                 lua_pushstring(L,"path");
347                 lua_pushstring(L,games[i].path.c_str());
348                 lua_settable(L, top_lvl2);
349
350                 lua_pushstring(L,"gamemods_path");
351                 lua_pushstring(L,games[i].gamemods_path.c_str());
352                 lua_settable(L, top_lvl2);
353
354                 lua_pushstring(L,"name");
355                 lua_pushstring(L,games[i].name.c_str());
356                 lua_settable(L, top_lvl2);
357
358                 lua_pushstring(L,"menuicon_path");
359                 lua_pushstring(L,games[i].menuicon_path.c_str());
360                 lua_settable(L, top_lvl2);
361
362                 lua_pushstring(L,"addon_mods_paths");
363                 lua_newtable(L);
364                 int table2 = lua_gettop(L);
365                 int internal_index=1;
366                 for (std::set<std::string>::iterator iter = games[i].addon_mods_paths.begin();
367                                 iter != games[i].addon_mods_paths.end(); iter++) {
368                         lua_pushnumber(L,internal_index);
369                         lua_pushstring(L,(*iter).c_str());
370                         lua_settable(L, table2);
371                         internal_index++;
372                 }
373                 lua_settable(L, top_lvl2);
374                 lua_settable(L, top);
375                 index++;
376         }
377         return 1;
378 }
379 /******************************************************************************/
380 int guiLuaApi::l_get_modstore_details(lua_State *L)
381 {
382         const char *modid       = luaL_checkstring(L, 1);
383
384         if (modid != 0) {
385                 Json::Value details;
386                 std::string url = "";
387                 try{
388                         url = g_settings->get("modstore_details_url");
389                 }
390                 catch(SettingNotFoundException &e) {
391                         lua_pushnil(L);
392                         return 1;
393                 }
394
395                 size_t idpos = url.find("*");
396                 url.erase(idpos,1);
397                 url.insert(idpos,modid);
398
399                 details = getModstoreUrl(url);
400
401                 ModStoreModDetails current_mod = readModStoreModDetails(details);
402
403                 if ( current_mod.valid) {
404                         lua_newtable(L);
405                         int top = lua_gettop(L);
406
407                         lua_pushstring(L,"id");
408                         lua_pushnumber(L,current_mod.id);
409                         lua_settable(L, top);
410
411                         lua_pushstring(L,"title");
412                         lua_pushstring(L,current_mod.title.c_str());
413                         lua_settable(L, top);
414
415                         lua_pushstring(L,"basename");
416                         lua_pushstring(L,current_mod.basename.c_str());
417                         lua_settable(L, top);
418
419                         lua_pushstring(L,"description");
420                         lua_pushstring(L,current_mod.description.c_str());
421                         lua_settable(L, top);
422
423                         lua_pushstring(L,"author");
424                         lua_pushstring(L,current_mod.author.username.c_str());
425                         lua_settable(L, top);
426
427                         lua_pushstring(L,"download_url");
428                         lua_pushstring(L,current_mod.versions[0].file.c_str());
429                         lua_settable(L, top);
430
431                         lua_pushstring(L,"license");
432                         lua_pushstring(L,current_mod.license.shortinfo.c_str());
433                         lua_settable(L, top);
434
435                         lua_pushstring(L,"rating");
436                         lua_pushnumber(L,current_mod.rating);
437                         lua_settable(L, top);
438
439                         //TODO depends
440
441                         //TODO softdepends
442                         return 1;
443                 }
444         }
445         return 0;
446 }
447
448 /******************************************************************************/
449 int guiLuaApi::l_get_modstore_list(lua_State *L)
450 {
451         GUIEngine* engine = get_engine(L);
452         assert(engine != 0);
453
454         std::string listtype = "local";
455
456         if (!lua_isnone(L,1)) {
457                 listtype = luaL_checkstring(L,1);
458         }
459         Json::Value mods;
460         std::string url = "";
461         try{
462                 url = g_settings->get("modstore_listmods_url");
463         }
464         catch(SettingNotFoundException &e) {
465                 lua_pushnil(L);
466                 return 1;
467         }
468
469         mods = getModstoreUrl(url);
470
471         std::vector<ModStoreMod> moddata = readModStoreList(mods);
472
473         lua_newtable(L);
474         int top = lua_gettop(L);
475         unsigned int index = 1;
476
477         for (unsigned int i = 0; i < moddata.size(); i++)
478         {
479                 if (moddata[i].valid) {
480                         lua_pushnumber(L,index);
481                         lua_newtable(L);
482
483                         int top_lvl2 = lua_gettop(L);
484
485                         lua_pushstring(L,"id");
486                         lua_pushnumber(L,moddata[i].id);
487                         lua_settable(L, top_lvl2);
488
489                         lua_pushstring(L,"title");
490                         lua_pushstring(L,moddata[i].title.c_str());
491                         lua_settable(L, top_lvl2);
492
493                         lua_pushstring(L,"basename");
494                         lua_pushstring(L,moddata[i].basename.c_str());
495                         lua_settable(L, top_lvl2);
496
497                         lua_settable(L, top);
498                         index++;
499                 }
500         }
501         return 1;
502 }
503
504 /******************************************************************************/
505 int guiLuaApi::l_get_favorites(lua_State *L)
506 {
507         GUIEngine* engine = get_engine(L);
508         assert(engine != 0);
509
510         std::string listtype = "local";
511
512         if (!lua_isnone(L,1)) {
513                 listtype = luaL_checkstring(L,1);
514         }
515
516         std::vector<ServerListSpec> servers;
517 #if USE_CURL
518         if(listtype == "online") {
519                 servers = ServerList::getOnline();
520         } else {
521                 servers = ServerList::getLocal();
522         }
523 #else
524         servers = ServerList::getLocal();
525 #endif
526
527         lua_newtable(L);
528         int top = lua_gettop(L);
529         unsigned int index = 1;
530
531         for (unsigned int i = 0; i < servers.size(); i++)
532         {
533                 lua_pushnumber(L,index);
534
535                 lua_newtable(L);
536                 int top_lvl2 = lua_gettop(L);
537
538                 if (servers[i]["clients"].asString().size()) {
539
540                         const char* clients_raw = servers[i]["clients"].asString().c_str();
541                         char* endptr = 0;
542                         int numbervalue = strtol(clients_raw,&endptr,10);
543
544                         if ((*clients_raw != 0) && (*endptr == 0)) {
545                                 lua_pushstring(L,"clients");
546                                 lua_pushnumber(L,numbervalue);
547                                 lua_settable(L, top_lvl2);
548                         }
549                 }
550
551                 if (servers[i]["clients_max"].asString().size()) {
552
553                         const char* clients_max_raw = servers[i]["clients"].asString().c_str();
554                         char* endptr = 0;
555                         int numbervalue = strtol(clients_max_raw,&endptr,10);
556
557                         if ((*clients_max_raw != 0) && (*endptr == 0)) {
558                                 lua_pushstring(L,"clients_max");
559                                 lua_pushnumber(L,numbervalue);
560                                 lua_settable(L, top_lvl2);
561                         }
562                 }
563
564                 if (servers[i]["version"].asString().size()) {
565                         lua_pushstring(L,"version");
566                         lua_pushstring(L,servers[i]["version"].asString().c_str());
567                         lua_settable(L, top_lvl2);
568                 }
569
570                 if (servers[i]["password"].asString().size()) {
571                         lua_pushstring(L,"password");
572                         lua_pushboolean(L,true);
573                         lua_settable(L, top_lvl2);
574                 }
575
576                 if (servers[i]["creative"].asString().size()) {
577                         lua_pushstring(L,"creative");
578                         lua_pushboolean(L,true);
579                         lua_settable(L, top_lvl2);
580                 }
581
582                 if (servers[i]["damage"].asString().size()) {
583                         lua_pushstring(L,"damage");
584                         lua_pushboolean(L,true);
585                         lua_settable(L, top_lvl2);
586                 }
587
588                 if (servers[i]["pvp"].asString().size()) {
589                         lua_pushstring(L,"pvp");
590                         lua_pushboolean(L,true);
591                         lua_settable(L, top_lvl2);
592                 }
593
594                 if (servers[i]["description"].asString().size()) {
595                         lua_pushstring(L,"description");
596                         lua_pushstring(L,servers[i]["description"].asString().c_str());
597                         lua_settable(L, top_lvl2);
598                 }
599
600                 if (servers[i]["name"].asString().size()) {
601                         lua_pushstring(L,"name");
602                         lua_pushstring(L,servers[i]["name"].asString().c_str());
603                         lua_settable(L, top_lvl2);
604                 }
605
606                 if (servers[i]["address"].asString().size()) {
607                         lua_pushstring(L,"address");
608                         lua_pushstring(L,servers[i]["address"].asString().c_str());
609                         lua_settable(L, top_lvl2);
610                 }
611
612                 if (servers[i]["port"].asString().size()) {
613                         lua_pushstring(L,"port");
614                         lua_pushstring(L,servers[i]["port"].asString().c_str());
615                         lua_settable(L, top_lvl2);
616                 }
617
618                 lua_settable(L, top);
619                 index++;
620         }
621         return 1;
622 }
623
624 /******************************************************************************/
625 int guiLuaApi::l_delete_favorite(lua_State *L)
626 {
627         GUIEngine* engine = get_engine(L);
628         assert(engine != 0);
629
630         std::vector<ServerListSpec> servers;
631
632         std::string listtype = "local";
633
634         if (!lua_isnone(L,2)) {
635                 listtype = luaL_checkstring(L,2);
636         }
637
638         if ((listtype != "local") &&
639                 (listtype != "online"))
640                 return 0;
641
642 #if USE_CURL
643         if(listtype == "online") {
644                 servers = ServerList::getOnline();
645         } else {
646                 servers = ServerList::getLocal();
647         }
648 #else
649         servers = ServerList::getLocal();
650 #endif
651
652         int fav_idx     = luaL_checkinteger(L,1) -1;
653
654         if ((fav_idx >= 0) &&
655                         (fav_idx < (int) servers.size())) {
656
657                 ServerList::deleteEntry(servers[fav_idx]);
658         }
659
660         return 0;
661 }
662
663 /******************************************************************************/
664 int guiLuaApi::l_show_keys_menu(lua_State *L)
665 {
666         GUIEngine* engine = get_engine(L);
667         assert(engine != 0);
668
669         GUIKeyChangeMenu *kmenu
670                 = new GUIKeyChangeMenu( engine->m_device->getGUIEnvironment(),
671                                                                 engine->m_parent,
672                                                                 -1,
673                                                                 engine->m_menumanager);
674         kmenu->drop();
675         return 0;
676 }
677
678 /******************************************************************************/
679 int guiLuaApi::l_setting_set(lua_State *L)
680 {
681         const char *name = luaL_checkstring(L, 1);
682         const char *value = luaL_checkstring(L, 2);
683         g_settings->set(name, value);
684         return 0;
685 }
686
687 /******************************************************************************/
688 int guiLuaApi::l_setting_get(lua_State *L)
689 {
690         const char *name = luaL_checkstring(L, 1);
691         try{
692                 std::string value = g_settings->get(name);
693                 lua_pushstring(L, value.c_str());
694         } catch(SettingNotFoundException &e){
695                 lua_pushnil(L);
696         }
697         return 1;
698 }
699
700 /******************************************************************************/
701 int guiLuaApi::l_setting_getbool(lua_State *L)
702 {
703         const char *name = luaL_checkstring(L, 1);
704         try{
705                 bool value = g_settings->getBool(name);
706                 lua_pushboolean(L, value);
707         } catch(SettingNotFoundException &e){
708                 lua_pushnil(L);
709         }
710         return 1;
711 }
712
713 /******************************************************************************/
714 int guiLuaApi::l_setting_setbool(lua_State *L)
715 {
716         const char *name = luaL_checkstring(L, 1);
717         bool value = lua_toboolean(L,2);
718
719         g_settings->setBool(name,value);
720
721         return 0;
722 }
723
724 /******************************************************************************/
725 int guiLuaApi::l_create_world(lua_State *L)
726 {
727         GUIEngine* engine = get_engine(L);
728         assert(engine != 0);
729
730         const char *name        = luaL_checkstring(L, 1);
731         int gameidx                     = luaL_checkinteger(L,2) -1;
732
733         std::string path = porting::path_user + DIR_DELIM
734                         "worlds" + DIR_DELIM
735                         + name;
736
737         std::vector<SubgameSpec> games = getAvailableGames();
738
739         if ((gameidx >= 0) &&
740                         (gameidx < (int) games.size())) {
741
742                 // Create world if it doesn't exist
743                 if(!initializeWorld(path, games[gameidx].id)){
744                         lua_pushstring(L, "Failed to initialize world");
745
746                 }
747                 else {
748                 lua_pushnil(L);
749                 }
750         }
751         else {
752                 lua_pushstring(L, "Invalid game index");
753         }
754         return 1;
755 }
756
757 /******************************************************************************/
758 int guiLuaApi::l_delete_world(lua_State *L)
759 {
760         GUIEngine* engine = get_engine(L);
761         assert(engine != 0);
762
763         int worldidx    = luaL_checkinteger(L,1) -1;
764
765         std::vector<WorldSpec> worlds = getAvailableWorlds();
766
767         if ((worldidx >= 0) &&
768                 (worldidx < (int) worlds.size())) {
769
770                 WorldSpec spec = worlds[worldidx];
771
772                 std::vector<std::string> paths;
773                 paths.push_back(spec.path);
774                 fs::GetRecursiveSubPaths(spec.path, paths);
775
776                 // Delete files
777                 if (!fs::DeletePaths(paths)) {
778                         lua_pushstring(L, "Failed to delete world");
779                 }
780                 else {
781                         lua_pushnil(L);
782                 }
783         }
784         else {
785                 lua_pushstring(L, "Invalid world index");
786         }
787         return 1;
788 }
789
790 /******************************************************************************/
791 int guiLuaApi::l_set_topleft_text(lua_State *L)
792 {
793         GUIEngine* engine = get_engine(L);
794         assert(engine != 0);
795
796         std::string text = "";
797
798         if (!lua_isnone(L,1) && !lua_isnil(L,1))
799                 text = luaL_checkstring(L, 1);
800
801         engine->setTopleftText(text);
802         return 0;
803 }
804
805 /******************************************************************************/
806 int guiLuaApi::l_get_modpath(lua_State *L)
807 {
808         //TODO this path may be controversial!
809         std::string modpath
810                         = fs::RemoveRelativePathComponents(porting::path_share + DIR_DELIM + "mods" + DIR_DELIM);
811         lua_pushstring(L, modpath.c_str());
812         return 1;
813 }
814
815 /******************************************************************************/
816 int guiLuaApi::l_get_gamepath(lua_State *L)
817 {
818         std::string gamepath
819                         = fs::RemoveRelativePathComponents(porting::path_share + DIR_DELIM + "games"    + DIR_DELIM);
820         lua_pushstring(L, gamepath.c_str());
821         return 1;
822 }
823
824 /******************************************************************************/
825 int guiLuaApi::l_get_dirlist(lua_State *L) {
826         const char *path        = luaL_checkstring(L, 1);
827         bool dironly            = lua_toboolean(L, 2);
828
829         std::vector<fs::DirListNode> dirlist = fs::GetDirListing(path);
830
831         unsigned int index = 1;
832         lua_newtable(L);
833         int table = lua_gettop(L);
834
835         for (unsigned int i=0;i< dirlist.size(); i++) {
836                 if ((dirlist[i].dir) || (dironly == false)) {
837                         lua_pushnumber(L,index);
838                         lua_pushstring(L,dirlist[i].name.c_str());
839                         lua_settable(L, table);
840                         index++;
841                 }
842         }
843
844         return 1;
845 }
846
847 /******************************************************************************/
848 int guiLuaApi::l_create_dir(lua_State *L) {
849         const char *path        = luaL_checkstring(L, 1);
850
851         if (guiLuaApi::isMinetestPath(path)) {
852                 lua_pushboolean(L,fs::CreateAllDirs(path));
853                 return 1;
854         }
855         lua_pushboolean(L,false);
856         return 1;
857 }
858
859 /******************************************************************************/
860 int guiLuaApi::l_delete_dir(lua_State *L) {
861         const char *path        = luaL_checkstring(L, 1);
862
863         std::string absolute_path = fs::RemoveRelativePathComponents(path);
864
865         if (guiLuaApi::isMinetestPath(absolute_path)) {
866                 lua_pushboolean(L,fs::RecursiveDelete(absolute_path));
867                 return 1;
868         }
869         lua_pushboolean(L,false);
870         return 1;
871 }
872
873 /******************************************************************************/
874 int guiLuaApi::l_copy_dir(lua_State *L) {
875         const char *source      = luaL_checkstring(L, 1);
876         const char *destination = luaL_checkstring(L, 2);
877
878         bool keep_source = true;
879
880         if ((!lua_isnone(L,3)) &&
881                         (!lua_isnil(L,3))) {
882                 keep_source = lua_toboolean(L,3);
883         }
884
885         std::string absolute_destination = fs::RemoveRelativePathComponents(destination);
886         std::string absolute_source = fs::RemoveRelativePathComponents(source);
887
888         if ((guiLuaApi::isMinetestPath(absolute_source)) &&
889                         (guiLuaApi::isMinetestPath(absolute_destination))) {
890                 bool retval = fs::CopyDir(absolute_source,absolute_destination);
891
892                 if (retval && (!keep_source)) {
893
894                         retval &= fs::RecursiveDelete(absolute_source);
895                 }
896                 lua_pushboolean(L,retval);
897                 return 1;
898         }
899         lua_pushboolean(L,false);
900         return 1;
901 }
902
903 /******************************************************************************/
904 int guiLuaApi::l_extract_zip(lua_State *L) {
905
906         GUIEngine* engine = get_engine(L);
907         assert(engine != 0);
908
909         const char *zipfile     = luaL_checkstring(L, 1);
910         const char *destination = luaL_checkstring(L, 2);
911
912         std::string absolute_destination = fs::RemoveRelativePathComponents(destination);
913
914         if (guiLuaApi::isMinetestPath(absolute_destination)) {
915                 fs::CreateAllDirs(absolute_destination);
916
917                 io::IFileSystem* fs = engine->m_device->getFileSystem();
918
919                 fs->addFileArchive(zipfile,true,false,io::EFAT_ZIP);
920
921                 assert(fs->getFileArchiveCount() > 0);
922
923                 /**********************************************************************/
924                 /* WARNING this is not threadsafe!!                                   */
925                 /**********************************************************************/
926                 io::IFileArchive* opened_zip =
927                         fs->getFileArchive(fs->getFileArchiveCount()-1);
928
929                 const io::IFileList* files_in_zip = opened_zip->getFileList();
930
931                 unsigned int number_of_files = files_in_zip->getFileCount();
932
933                 for (unsigned int i=0; i < number_of_files;  i++) {
934                         std::string fullpath = destination;
935                         fullpath += DIR_DELIM;
936                         fullpath += files_in_zip->getFullFileName(i).c_str();
937
938                         if (files_in_zip->isDirectory(i)) {
939                                 if (! fs::CreateAllDirs(fullpath) ) {
940                                         fs->removeFileArchive(fs->getFileArchiveCount()-1);
941                                         lua_pushboolean(L,false);
942                                         return 1;
943                                 }
944                         }
945                         else {
946                                 io::IReadFile* toread = opened_zip->createAndOpenFile(i);
947
948                                 FILE *targetfile = fopen(fullpath.c_str(),"wb");
949
950                                 if (targetfile == NULL) {
951                                         fs->removeFileArchive(fs->getFileArchiveCount()-1);
952                                         lua_pushboolean(L,false);
953                                         return 1;
954                                 }
955
956                                 char read_buffer[1024];
957                                 unsigned int total_read = 0;
958
959                                 while (total_read < toread->getSize()) {
960
961                                         unsigned int bytes_read =
962                                                         toread->read(read_buffer,sizeof(read_buffer));
963                                         unsigned int bytes_written;
964                                         if ((bytes_read < 0 ) ||
965                                                 (bytes_written = fwrite(read_buffer, 1, bytes_read, targetfile) != bytes_read))
966                                         {
967                                                 fclose(targetfile);
968                                                 fs->removeFileArchive(fs->getFileArchiveCount()-1);
969                                                 lua_pushboolean(L,false);
970                                                 return 1;
971                                         }
972                                         total_read += bytes_read;
973                                 }
974
975                                 fclose(targetfile);
976                         }
977
978                 }
979
980                 fs->removeFileArchive(fs->getFileArchiveCount()-1);
981                 lua_pushboolean(L,true);
982                 return 1;
983         }
984
985         lua_pushboolean(L,false);
986         return 1;
987 }
988
989 /******************************************************************************/
990 int guiLuaApi::l_get_scriptdir(lua_State *L) {
991         GUIEngine* engine = get_engine(L);
992         assert(engine != 0);
993
994         lua_pushstring(L,engine->getScriptDir().c_str());
995         return 1;
996 }
997
998 /******************************************************************************/
999 bool guiLuaApi::isMinetestPath(std::string path) {
1000
1001
1002         if (fs::PathStartsWith(path,fs::TempPath()))
1003                 return true;
1004
1005         /* games */
1006         if (fs::PathStartsWith(path,fs::RemoveRelativePathComponents(porting::path_share + DIR_DELIM + "games")))
1007                 return true;
1008
1009         /* mods */
1010         if (fs::PathStartsWith(path,fs::RemoveRelativePathComponents(porting::path_share + DIR_DELIM + "mods")))
1011                 return true;
1012
1013         /* worlds */
1014         if (fs::PathStartsWith(path,fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM + "worlds")))
1015                 return true;
1016
1017
1018         return false;
1019 }
1020
1021 /******************************************************************************/
1022 int guiLuaApi::l_show_file_open_dialog(lua_State *L) {
1023
1024         GUIEngine* engine = get_engine(L);
1025         assert(engine != 0);
1026
1027         const char *formname= luaL_checkstring(L, 1);
1028         const char *title       = luaL_checkstring(L, 2);
1029
1030         GUIFileSelectMenu* fileOpenMenu =
1031                 new GUIFileSelectMenu(engine->m_device->getGUIEnvironment(),
1032                                                                 engine->m_parent,
1033                                                                 -1,
1034                                                                 engine->m_menumanager,
1035                                                                 title,
1036                                                                 formname);
1037         fileOpenMenu->setTextDest(engine->m_buttonhandler);
1038         fileOpenMenu->drop();
1039         return 0;
1040 }
1041
1042 /******************************************************************************/
1043 int guiLuaApi::l_get_version(lua_State *L) {
1044         lua_pushstring(L,VERSION_STRING);
1045         return 1;
1046 }
1047
1048 /******************************************************************************/
1049 int guiLuaApi::l_download_file(lua_State *L) {
1050         GUIEngine* engine = get_engine(L);
1051         assert(engine != 0);
1052
1053         const char *url    = luaL_checkstring(L, 1);
1054         const char *target = luaL_checkstring(L, 2);
1055
1056         //check path
1057         std::string absolute_destination = fs::RemoveRelativePathComponents(target);
1058
1059         if (guiLuaApi::isMinetestPath(absolute_destination)) {
1060                 if (engine->downloadFile(url,absolute_destination)) {
1061                         lua_pushboolean(L,true);
1062                         return 1;
1063                 }
1064         }
1065         lua_pushboolean(L,false);
1066         return 1;
1067 }