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/location.h"
19 #include "session/session.h"
20 #include "util/memory.h"
21 #include "util/string.h"
23 extern PyObject
*python_hooks
;
26 * A utility function for script_hook_url() and script_hook_get_proxy():
27 * Free a char * and replace it with the contents of a Python string.
28 * (Py_None is ignored.)
32 replace_with_python_string(unsigned char **dest
, PyObject
*object
)
36 if (object
== Py_None
) return object
;
38 str
= (unsigned char *) PyString_AsString(object
);
39 if (!str
) return NULL
;
42 if (!str
) return PyErr_NoMemory();
44 mem_free_set(dest
, str
);
48 /* Call a Python hook for a goto-url or follow-url event. */
50 static enum evhook_status
51 script_hook_url(va_list ap
, void *data
)
53 unsigned char **url
= va_arg(ap
, unsigned char **);
54 struct session
*ses
= va_arg(ap
, struct session
*);
56 struct session
*saved_python_ses
= python_ses
;
59 evhook_use_params(url
&& ses
);
61 if (!python_hooks
|| !url
|| !*url
62 || !PyObject_HasAttrString(python_hooks
, method
))
63 return EVENT_HOOK_STATUS_NEXT
;
68 * Historical note: The only reason the goto and follow hooks are
69 * treated differently is to maintain backwards compatibility for
70 * people who already have a goto_url_hook() function in hooks.py
71 * that expects a second argument. If we were starting over from
72 * scratch, we could treat the goto and follow hooks identically and
73 * simply pass @url as the sole argument in both cases; the Python
74 * code for the goto hook no longer needs its @current_url argument
75 * since it could instead determine the current URL by calling the
76 * Python interpreter's elinks.current_url() function.
78 if (!strcmp(method
, "goto_url_hook")) {
79 unsigned char *current_url
= NULL
;
81 if (python_ses
&& have_location(python_ses
))
82 current_url
= struri(cur_loc(ses
)->vs
.uri
);
84 result
= PyObject_CallMethod(python_hooks
, method
, "ss", *url
,
87 result
= PyObject_CallMethod(python_hooks
, method
, "s", *url
);
90 if (!result
|| !replace_with_python_string(url
, result
))
95 python_ses
= saved_python_ses
;
97 return EVENT_HOOK_STATUS_NEXT
;
100 /* Call a Python hook for a pre-format-html event. */
102 static enum evhook_status
103 script_hook_pre_format_html(va_list ap
, void *data
)
105 struct session
*ses
= va_arg(ap
, struct session
*);
106 struct cache_entry
*cached
= va_arg(ap
, struct cache_entry
*);
107 struct fragment
*fragment
= get_cache_fragment(cached
);
108 unsigned char *url
= struri(cached
->uri
);
109 char *method
= "pre_format_html_hook";
110 struct session
*saved_python_ses
= python_ses
;
114 evhook_use_params(ses
&& cached
);
116 if (!python_hooks
|| !cached
->length
|| !*fragment
->data
117 || !PyObject_HasAttrString(python_hooks
, method
))
118 return EVENT_HOOK_STATUS_NEXT
;
122 result
= PyObject_CallMethod(python_hooks
, method
, "ss#", url
,
123 fragment
->data
, fragment
->length
);
124 if (!result
) goto error
;
126 if (result
!= Py_None
) {
130 if (PyString_AsStringAndSize(result
, (char **) &str
, &len
) != 0)
133 (void) add_fragment(cached
, 0, str
, len
);
134 normalize_cache_entry(cached
, len
);
140 if (!success
) alert_python_error();
144 python_ses
= saved_python_ses
;
146 return EVENT_HOOK_STATUS_NEXT
;
149 /* Call a Python hook for a get-proxy event. */
151 static enum evhook_status
152 script_hook_get_proxy(va_list ap
, void *data
)
154 unsigned char **proxy
= va_arg(ap
, unsigned char **);
155 unsigned char *url
= va_arg(ap
, unsigned char *);
156 char *method
= "proxy_for_hook";
159 evhook_use_params(proxy
&& url
);
161 if (!python_hooks
|| !proxy
|| !url
162 || !PyObject_HasAttrString(python_hooks
, method
))
163 return EVENT_HOOK_STATUS_NEXT
;
165 result
= PyObject_CallMethod(python_hooks
, method
, "s", url
);
167 if (!result
|| !replace_with_python_string(proxy
, result
))
168 alert_python_error();
172 return EVENT_HOOK_STATUS_NEXT
;
175 /* Call a Python hook for a quit event. */
177 static enum evhook_status
178 script_hook_quit(va_list ap
, void *data
)
180 char *method
= "quit_hook";
183 if (!python_hooks
|| !PyObject_HasAttrString(python_hooks
, method
))
184 return EVENT_HOOK_STATUS_NEXT
;
186 result
= PyObject_CallMethod(python_hooks
, method
, NULL
);
187 if (!result
) alert_python_error();
191 return EVENT_HOOK_STATUS_NEXT
;
194 struct event_hook_info python_scripting_hooks
[] = {
195 { "goto-url", 0, script_hook_url
, "goto_url_hook" },
196 { "follow-url", 0, script_hook_url
, "follow_url_hook" },
197 { "pre-format-html", 0, script_hook_pre_format_html
, NULL
},
198 { "get-proxy", 0, script_hook_get_proxy
, NULL
},
199 { "quit", 0, script_hook_quit
, NULL
},
200 NULL_EVENT_HOOK_INFO
,