1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-11-04 08:17:17 -05:00
elinks/src/scripting/lua/hooks.c
2022-01-30 19:19:20 +01:00

247 lines
5.4 KiB
C

/* Lua scripting hooks */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#include <lauxlib.h>
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
extern "C" {
#endif
#include <lua.h>
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
extern "C" {
#endif
#include <lualib.h>
#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,
};