1 /*
2  * luah.c - Lua helper functions
3  *
4  * Copyright © 2010-2011 Mason Larobina <mason.larobina@gmail.com>
5  * Copyright © 2008-2009 Julien Danjou <julien@danjou.info>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #include "ipc.h"
23 #include "luah.h"
24 #include "log.h"
25 #include "common/luah.h"
26 #include "common/luautil.h"
27 #include "common/luayield.h"
28 
29 /* include clib headers */
30 #include "clib/download.h"
31 #include "clib/luakit.h"
32 #include "clib/request.h"
33 #include "clib/sqlite3.h"
34 #include "clib/soup.h"
35 #include "clib/unique.h"
36 #include "clib/widget.h"
37 #include "clib/xdg.h"
38 #include "clib/stylesheet.h"
39 #include "clib/web_module.h"
40 #include "clib/msg.h"
41 #include "common/clib/ipc.h"
42 #include "common/clib/timer.h"
43 #include "common/clib/regex.h"
44 #include "common/clib/utf8.h"
45 #include "globalconf.h"
46 
47 #include <glib.h>
48 #include <gtk/gtk.h>
49 #include <stdlib.h>
50 
51 void
luaH_modifier_table_push(lua_State * L,guint state)52 luaH_modifier_table_push(lua_State *L, guint state) {
53     gint i = 1;
54     lua_newtable(L);
55     if (state & GDK_MODIFIER_MASK) {
56 
57 #define MODKEY(key, name)           \
58     if (state & GDK_##key##_MASK) { \
59         lua_pushstring(L, name);    \
60         lua_rawseti(L, -2, i++);    \
61     }
62 
63         MODKEY(SHIFT, "Shift");
64         MODKEY(LOCK, "Lock");
65         MODKEY(CONTROL, "Control");
66         MODKEY(MOD1, "Mod1");
67         MODKEY(MOD2, "Mod2");
68         MODKEY(MOD3, "Mod3");
69         MODKEY(MOD4, "Mod4");
70         MODKEY(MOD5, "Mod5");
71 
72 #undef MODKEY
73 
74     }
75 }
76 
77 void
luaH_keystr_push(lua_State * L,guint keyval)78 luaH_keystr_push(lua_State *L, guint keyval)
79 {
80     gchar ucs[7];
81     guint ulen;
82     guint32 ukval = gdk_keyval_to_unicode(keyval);
83 
84     /* check for printable unicode character */
85     if (g_unichar_isgraph(ukval)) {
86         ulen = g_unichar_to_utf8(ukval, ucs);
87         ucs[ulen] = 0;
88         lua_pushstring(L, ucs);
89     }
90     /* sent keysym for non-printable characters */
91     else
92         lua_pushstring(L, gdk_keyval_name(keyval));
93 }
94 
95 void
luaH_init(gchar ** uris)96 luaH_init(gchar ** uris)
97 {
98     /* Lua VM init */
99     lua_State *L = common.L = luaL_newstate();
100 
101     /* Set panic fuction */
102     lua_atpanic(L, luaH_panic);
103 
104     luaL_openlibs(L);
105 
106     luaH_fixups(L);
107 
108     luaH_object_setup(L);
109 
110     /* Export luakit lib */
111     luakit_lib_setup(L);
112 
113     /* Export xdg lib */
114     xdg_lib_setup(L);
115 
116     /* Export soup lib */
117     soup_lib_setup(L);
118 
119     if (!globalconf.nounique)
120         /* Export unique lib */
121         unique_lib_setup(L);
122 
123     /* Export widget */
124     widget_class_setup(L);
125 
126     /* Export download */
127     download_class_setup(L);
128 
129     /* Export sqlite3 */
130     sqlite3_class_setup(L);
131 
132     /* Export timer */
133     timer_class_setup(L);
134 
135     /* Export regex */
136     regex_class_setup(L);
137 
138     /* Export utf8 */
139     utf8_lib_setup(L);
140 
141     /* Export request */
142     request_class_setup(L);
143 
144     /* Export stylesheet */
145     stylesheet_class_setup(L);
146 
147     /* Export web module */
148     web_module_lib_setup(L);
149     ipc_channel_class_setup(L);
150 
151     /* Export web module */
152     msg_lib_setup(L);
153 
154     luaH_yield_setup(L);
155 
156     /* add Lua search paths */
157     luaH_add_paths(L, globalconf.config_dir);
158 
159     /* push a table of the startup uris */
160     const gchar *uri;
161     lua_newtable(L);
162     for (gint i = 0; uris && (uri = uris[i]); i++) {
163         lua_pushstring(L, uri);
164         lua_rawseti(L, -2, i + 1);
165     }
166     lua_setglobal(L, "uris");
167 }
168 
169 static gboolean
luaH_loadrc(const gchar * confpath,gboolean run)170 luaH_loadrc(const gchar *confpath, gboolean run)
171 {
172     info("Loading rc: %s", confpath);
173 
174     lua_State *L = common.L;
175 
176     if (luaL_loadfile(L, confpath)) {
177         error("Error loading rc: %s", lua_tostring(L, -1));
178         return FALSE;
179     }
180 
181     if (!run) {
182         lua_pop(L, 1);
183         return TRUE;
184     }
185 
186     return luaH_dofunction(L, 0, 0);
187 }
188 
189 /* Load a configuration file. */
190 gboolean
luaH_parserc(const gchar * confpath,gboolean run)191 luaH_parserc(const gchar *confpath, gboolean run)
192 {
193     const gchar* const *config_dirs = NULL;
194     gboolean ret = FALSE;
195     GPtrArray *paths = NULL;
196 
197     /* try to load, return if it's ok */
198     if (confpath) {
199         ret = luaH_loadrc(confpath, run);
200         goto bailout;
201     }
202 
203     /* compile list of config search paths */
204     paths = g_ptr_array_new_with_free_func(g_free);
205 
206 #if DEVELOPMENT_PATHS
207     /* allows for testing luakit in the project directory */
208     g_ptr_array_add(paths, g_strdup("./config/rc.lua"));
209 #endif
210 
211     /* search users config dir (see: XDG_CONFIG_HOME) */
212     g_ptr_array_add(paths, g_build_filename(globalconf.config_dir, "rc.lua", NULL));
213 
214     /* search system config dirs (see: XDG_CONFIG_DIRS) */
215     config_dirs = g_get_system_config_dirs();
216     for(; *config_dirs; config_dirs++)
217         g_ptr_array_add(paths, g_build_filename(*config_dirs, "luakit", "rc.lua", NULL));
218 
219     /* get continuation variable; bail out if invalid */
220     char *i_str = getenv("LUAKIT_NEXT_CONFIG_INDEX");
221     gint i = i_str ? atoi(i_str) : 0;
222     if (i_str && (i <= 0 || i >= (gint)paths->len))
223         goto bailout;
224 
225     /* Loop through paths until we have a config that exists: avoid needless execs */
226     for (; i < (gint)paths->len; i++) {
227         const gchar *path = paths->pdata[i];
228         if (file_exists(path))
229             break;
230         verbose("rc file '%s' does not exist", path);
231     }
232 
233     if (i == (gint)paths->len) {
234         warn("couldn't load any rc file");
235         goto bailout;
236     }
237 
238     /* attempt to load the indicated config file */
239     const gchar *path = paths->pdata[i++];
240     if (luaH_loadrc(path, run)) {
241         unsetenv("LUAKIT_NEXT_CONFIG_INDEX");
242         globalconf.confpath = g_strdup(path);
243         ret = TRUE;
244         goto bailout;
245     } else
246         warn("loading rc '%s' failed, falling back...", path);
247 
248     /* set continuation variable for replacement process */
249     i_str = g_strdup_printf("%i", i);
250     setenv("LUAKIT_NEXT_CONFIG_INDEX", i_str, TRUE);
251     g_free(i_str);
252 
253     /* exec path: escape spaces (why?) */
254     gchar **parts = g_strsplit(globalconf.execpath, " ", -1);
255     gchar *escaped_execpath = g_strjoinv("\\ ", parts);
256     g_strfreev(parts);
257 
258     /* rebuild argv */
259     GPtrArray *argv = globalconf.argv;
260     g_ptr_array_insert(argv, 0, escaped_execpath);
261     g_ptr_array_add(argv, NULL);
262 
263     verbose("exec: %s", g_strjoinv(" ", (gchar**)argv->pdata));
264 
265     char *log_dump_file = log_dump_queued_emissions();
266     if (log_dump_file) {
267         setenv("LUAKIT_QUEUED_EMISSIONS_FILE", log_dump_file, TRUE);
268         g_free(log_dump_file);
269     }
270     ipc_remove_socket_file();
271     execvp(escaped_execpath, (gchar**)argv->pdata);
272 
273 bailout:
274 
275     if (paths) g_ptr_array_free(paths, TRUE);
276     return ret;
277 }
278 
279 // vim: ft=c:et:sw=4:ts=8:sts=4:tw=80
280