0
0
mirror of https://github.com/rkd77/elinks.git synced 2025-06-30 22:19:29 -04:00
2008-06-09 23:18:03 +03:00

185 lines
4.4 KiB
C

/* Python scripting hooks */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <Python.h>
#include <stdarg.h>
#include <string.h>
#include "elinks.h"
#include "cache/cache.h"
#include "main/event.h"
#include "protocol/uri.h"
#include "scripting/python/core.h"
#include "session/session.h"
#include "util/memory.h"
#include "util/string.h"
extern PyObject *python_hooks;
/*
* A utility function for script_hook_url() and script_hook_get_proxy():
* Free a char * and replace it with the contents of a Python string.
* (Py_None is ignored.)
*/
static PyObject *
replace_with_python_string(unsigned char **dest, PyObject *object)
{
unsigned char *str;
if (object == Py_None) return object;
str = (unsigned char *) PyString_AsString(object);
if (!str) return NULL;
str = stracpy(str);
if (!str) return PyErr_NoMemory();
mem_free_set(dest, str);
return object;
}
/* Call a Python hook for a goto-url or follow-url event. */
static enum evhook_status
script_hook_url(va_list ap, void *data)
{
unsigned char **url = va_arg(ap, unsigned char **);
struct session *ses = va_arg(ap, struct session *);
char *method = data;
struct session *saved_python_ses = python_ses;
PyObject *result;
evhook_use_params(url && ses);
if (!python_hooks || !url || !*url
|| !PyObject_HasAttrString(python_hooks, method))
return EVENT_HOOK_STATUS_NEXT;
python_ses = ses;
result = PyObject_CallMethod(python_hooks, method, "s", *url);
if (!result || !replace_with_python_string(url, result))
alert_python_error();
Py_XDECREF(result);
python_ses = saved_python_ses;
return EVENT_HOOK_STATUS_NEXT;
}
/* Call a Python hook for a pre-format-html event. */
static enum evhook_status
script_hook_pre_format_html(va_list ap, void *data)
{
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);
unsigned char *url = struri(cached->uri);
char *method = "pre_format_html_hook";
struct session *saved_python_ses = python_ses;
PyObject *result;
int success = 0;
evhook_use_params(ses && cached);
if (!python_hooks || !cached->length || !*fragment->data
|| !PyObject_HasAttrString(python_hooks, method))
return EVENT_HOOK_STATUS_NEXT;
python_ses = ses;
result = PyObject_CallMethod(python_hooks, method, "ss#", url,
fragment->data, fragment->length);
if (!result) goto error;
if (result != Py_None) {
unsigned char *str;
Py_ssize_t len;
if (PyString_AsStringAndSize(result, (char **) &str, &len) != 0)
goto error;
/* This assumes the Py_ssize_t len is not too large to
* fit in the off_t parameter of normalize_cache_entry().
* add_fragment() itself seems to assume the same thing,
* and there is no standard OFF_MAX macro against which
* ELinks could check the value. */
(void) add_fragment(cached, 0, str, len);
normalize_cache_entry(cached, len);
}
success = 1;
error:
if (!success) alert_python_error();
Py_XDECREF(result);
python_ses = saved_python_ses;
return EVENT_HOOK_STATUS_NEXT;
}
/* Call a Python hook for a get-proxy event. */
static enum evhook_status
script_hook_get_proxy(va_list ap, void *data)
{
unsigned char **proxy = va_arg(ap, unsigned char **);
unsigned char *url = va_arg(ap, unsigned char *);
char *method = "proxy_for_hook";
PyObject *result;
evhook_use_params(proxy && url);
if (!python_hooks || !proxy || !url
|| !PyObject_HasAttrString(python_hooks, method))
return EVENT_HOOK_STATUS_NEXT;
result = PyObject_CallMethod(python_hooks, method, "s", url);
if (!result || !replace_with_python_string(proxy, result))
alert_python_error();
Py_XDECREF(result);
return EVENT_HOOK_STATUS_NEXT;
}
/* Call a Python hook for a quit event. */
static enum evhook_status
script_hook_quit(va_list ap, void *data)
{
char *method = "quit_hook";
PyObject *result;
if (!python_hooks || !PyObject_HasAttrString(python_hooks, method))
return EVENT_HOOK_STATUS_NEXT;
result = PyObject_CallMethod(python_hooks, method, NULL);
if (!result) alert_python_error();
Py_XDECREF(result);
return EVENT_HOOK_STATUS_NEXT;
}
struct event_hook_info python_scripting_hooks[] = {
{ "goto-url", 0, script_hook_url, "goto_url_hook" },
{ "follow-url", 0, script_hook_url, "follow_url_hook" },
{ "pre-format-html", 0, script_hook_pre_format_html, NULL },
{ "get-proxy", 0, script_hook_get_proxy, NULL },
{ "quit", 0, script_hook_quit, NULL },
NULL_EVENT_HOOK_INFO,
};