1 /* Python scripting hooks */
14 #include "cache/cache.h"
15 #include "main/event.h"
16 #include "protocol/uri.h"
17 #include "scripting/python/core.h"
18 #include "session/session.h"
19 #include "util/memory.h"
20 #include "util/string.h"
22 extern PyObject
*python_hooks
;
25 * A utility function for script_hook_url() and script_hook_get_proxy():
26 * Free a char * and replace it with the contents of a Python string.
27 * (Py_None is ignored.)
31 replace_with_python_string(unsigned char **dest
, PyObject
*object
)
35 if (object
== Py_None
) return object
;
37 str
= (unsigned char *) PyString_AsString(object
);
38 if (!str
) return NULL
;
41 if (!str
) return PyErr_NoMemory();
43 mem_free_set(dest
, str
);
47 /* Call a Python hook for a goto-url or follow-url event. */
49 static enum evhook_status
50 script_hook_url(va_list ap
, void *data
)
52 unsigned char **url
= va_arg(ap
, unsigned char **);
53 struct session
*ses
= va_arg(ap
, struct session
*);
55 struct session
*saved_python_ses
= python_ses
;
58 evhook_use_params(url
&& ses
);
60 if (!python_hooks
|| !url
|| !*url
61 || !PyObject_HasAttrString(python_hooks
, method
))
62 return EVENT_HOOK_STATUS_NEXT
;
66 result
= PyObject_CallMethod(python_hooks
, method
, "s", *url
);
68 if (!result
|| !replace_with_python_string(url
, result
))
73 python_ses
= saved_python_ses
;
75 return EVENT_HOOK_STATUS_NEXT
;
78 /* Call a Python hook for a pre-format-html event. */
80 static enum evhook_status
81 script_hook_pre_format_html(va_list ap
, void *data
)
83 struct session
*ses
= va_arg(ap
, struct session
*);
84 struct cache_entry
*cached
= va_arg(ap
, struct cache_entry
*);
85 struct fragment
*fragment
= get_cache_fragment(cached
);
86 unsigned char *url
= struri(cached
->uri
);
87 char *method
= "pre_format_html_hook";
88 struct session
*saved_python_ses
= python_ses
;
92 evhook_use_params(ses
&& cached
);
94 if (!python_hooks
|| !cached
->length
|| !*fragment
->data
95 || !PyObject_HasAttrString(python_hooks
, method
))
96 return EVENT_HOOK_STATUS_NEXT
;
100 result
= PyObject_CallMethod(python_hooks
, method
, "ss#", url
,
101 fragment
->data
, fragment
->length
);
102 if (!result
) goto error
;
104 if (result
!= Py_None
) {
108 if (PyString_AsStringAndSize(result
, (char **) &str
, &len
) != 0)
111 /* This assumes the Py_ssize_t len is not too large to
112 * fit in the off_t parameter of normalize_cache_entry().
113 * add_fragment() itself seems to assume the same thing,
114 * and there is no standard OFF_MAX macro against which
115 * ELinks could check the value. */
116 (void) add_fragment(cached
, 0, str
, len
);
117 normalize_cache_entry(cached
, len
);
123 if (!success
) alert_python_error();
127 python_ses
= saved_python_ses
;
129 return EVENT_HOOK_STATUS_NEXT
;
132 /* Call a Python hook for a get-proxy event. */
134 static enum evhook_status
135 script_hook_get_proxy(va_list ap
, void *data
)
137 unsigned char **proxy
= va_arg(ap
, unsigned char **);
138 unsigned char *url
= va_arg(ap
, unsigned char *);
139 char *method
= "proxy_for_hook";
142 evhook_use_params(proxy
&& url
);
144 if (!python_hooks
|| !proxy
|| !url
145 || !PyObject_HasAttrString(python_hooks
, method
))
146 return EVENT_HOOK_STATUS_NEXT
;
148 result
= PyObject_CallMethod(python_hooks
, method
, "s", url
);
150 if (!result
|| !replace_with_python_string(proxy
, result
))
151 alert_python_error();
155 return EVENT_HOOK_STATUS_NEXT
;
158 /* Call a Python hook for a quit event. */
160 static enum evhook_status
161 script_hook_quit(va_list ap
, void *data
)
163 char *method
= "quit_hook";
166 if (!python_hooks
|| !PyObject_HasAttrString(python_hooks
, method
))
167 return EVENT_HOOK_STATUS_NEXT
;
169 result
= PyObject_CallMethod(python_hooks
, method
, NULL
);
170 if (!result
) alert_python_error();
174 return EVENT_HOOK_STATUS_NEXT
;
177 struct event_hook_info python_scripting_hooks
[] = {
178 { "goto-url", 0, script_hook_url
, "goto_url_hook" },
179 { "follow-url", 0, script_hook_url
, "follow_url_hook" },
180 { "pre-format-html", 0, script_hook_pre_format_html
, NULL
},
181 { "get-proxy", 0, script_hook_get_proxy
, NULL
},
182 { "quit", 0, script_hook_quit
, NULL
},
183 NULL_EVENT_HOOK_INFO
,