/* Lua scripting hooks */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef __cplusplus extern "C" { #endif #include #ifdef __cplusplus } #endif #ifdef __cplusplus extern "C" { #endif #include #ifdef __cplusplus } #endif #ifdef __cplusplus extern "C" { #endif #include #ifdef __cplusplus } #endif #include "elinks.h" #include "cache/cache.h" #include "main/event.h" #include "protocol/uri.h" #include "scripting/lua/core.h" #include "scripting/lua/hooks.h" #include "session/location.h" #include "session/session.h" #include "util/string.h" /* The events that will trigger the functions below and what they are expected * to do is explained in doc/events.txt */ static enum evhook_status script_hook_goto_url(va_list ap, void *data) { lua_State *L = lua_state; char **url = va_arg(ap, char **); struct session *ses = va_arg(ap, struct session *); int err; if (*url == NULL) return EVENT_HOOK_STATUS_NEXT; lua_getglobal(L, "goto_url_hook"); if (lua_isnil(L, -1)) { /* The function is not defined */ lua_pop(L, 1); return EVENT_HOOK_STATUS_NEXT; } lua_pushstring(L, *url); if (!ses || !have_location(ses)) { lua_pushnil(L); } else { lua_pushstring(L, struri(cur_loc(ses)->vs.uri)); } if (prepare_lua(ses)) return EVENT_HOOK_STATUS_NEXT; err = lua_pcall(L, 2, 1, 0); finish_lua(); if (err) return EVENT_HOOK_STATUS_NEXT; if (lua_isstring(L, -1)) { char *new_url; new_url = stracpy((char *) lua_tostring(L, -1)); if (new_url) { mem_free_set(url, new_url); } } else if (lua_isnil(L, -1)) { (*url)[0] = 0; } else { alert_lua_error("goto_url_hook must return a string or nil"); } lua_pop(L, 1); return EVENT_HOOK_STATUS_NEXT; } static enum evhook_status script_hook_follow_url(va_list ap, void *data) { lua_State *L = lua_state; char **url = va_arg(ap, char **); struct session *ses = va_arg(ap, struct session *); int err; if (*url == NULL) return EVENT_HOOK_STATUS_NEXT; lua_getglobal(L, "follow_url_hook"); if (lua_isnil(L, -1)) { /* The function is not defined */ lua_pop(L, 1); return EVENT_HOOK_STATUS_NEXT; } lua_pushstring(L, *url); if (prepare_lua(ses)) return EVENT_HOOK_STATUS_NEXT; err = lua_pcall(L, 1, 1, 0); finish_lua(); if (err) return EVENT_HOOK_STATUS_NEXT; if (lua_isstring(L, -1)) { char *new_url; new_url = stracpy((char *) lua_tostring(L, -1)); if (new_url) { mem_free_set(url, new_url); } } else if (lua_isnil(L, -1)) { (*url)[0] = 0; } else { alert_lua_error("follow_url_hook must return a string or nil"); } lua_pop(L, 1); return EVENT_HOOK_STATUS_NEXT; } static enum evhook_status script_hook_pre_format_html(va_list ap, void *data) { lua_State *L = lua_state; struct session *ses = va_arg(ap, struct session *); struct cache_entry *cached = va_arg(ap, struct cache_entry *); struct fragment *fragment = get_cache_fragment(cached); char *url = struri(cached->uri); int err; if (!cached->length || !*fragment->data) return EVENT_HOOK_STATUS_NEXT; lua_getglobal(L, "pre_format_html_hook"); if (lua_isnil(L, -1)) { /* The function is not defined */ lua_pop(L, 1); return EVENT_HOOK_STATUS_NEXT; } lua_pushstring(L, url); lua_pushlstring(L, fragment->data, fragment->length); if (prepare_lua(ses)) return EVENT_HOOK_STATUS_NEXT; err = lua_pcall(L, 2, 1, 0); finish_lua(); if (err) return EVENT_HOOK_STATUS_NEXT; if (lua_isstring(L, -1)) { #if LUA_VERSION_NUM > 501 int len = lua_rawlen(L, -1); #else int len = lua_strlen(L, -1); #endif add_fragment(cached, 0, (char *) lua_tostring(L, -1), len); normalize_cache_entry(cached, len); } else if (!lua_isnil(L, -1)) { alert_lua_error("pre_format_html_hook must return a string or nil"); } lua_pop(L, 1); return EVENT_HOOK_STATUS_NEXT; } /* The Lua function can return: * - "PROXY:PORT" to use the specified proxy * - "" to not use any proxy * - nil to use the default proxies */ static enum evhook_status script_hook_get_proxy(va_list ap, void *data) { lua_State *L = lua_state; char **new_proxy_url = va_arg(ap, char **); char *url = va_arg(ap, char *); int err; if (!new_proxy_url || !url) return EVENT_HOOK_STATUS_NEXT; lua_getglobal(L, "proxy_for_hook"); if (lua_isnil(L, -1)) { /* The function is not defined */ lua_pop(L, 1); return EVENT_HOOK_STATUS_NEXT; } lua_pushstring(L, url); if (prepare_lua(NULL)) return EVENT_HOOK_STATUS_NEXT; err = lua_pcall(L, 1, 1, 0); finish_lua(); if (err) return EVENT_HOOK_STATUS_NEXT; if (lua_isstring(L, -1)) { mem_free_set(new_proxy_url, stracpy((char *) lua_tostring(L, -1))); } else if (lua_isnil(L, -1)) { mem_free_set(new_proxy_url, NULL); } else { alert_lua_error("proxy_hook must return a string or nil"); } lua_pop(L, 1); return EVENT_HOOK_STATUS_NEXT; } static enum evhook_status script_hook_quit(va_list ap, void *data) { if (!prepare_lua(NULL)) { (void)luaL_dostring(lua_state, "if quit_hook then quit_hook() end"); finish_lua(); } return EVENT_HOOK_STATUS_NEXT; } struct event_hook_info lua_scripting_hooks[] = { { "goto-url", 0, script_hook_goto_url, NULL }, { "follow-url", 0, script_hook_follow_url, NULL }, { "pre-format-html", 0, script_hook_pre_format_html, NULL }, { "get-proxy", 0, script_hook_get_proxy, NULL }, { "quit", 0, script_hook_quit, NULL }, { "dialog-lua-console", 0, dialog_lua_console, NULL }, { "free-history", 0, free_lua_console_history, NULL }, NULL_EVENT_HOOK_INFO, };