Cast to (const char *) in strrchr calls
[elinks.git] / src / scripting / ruby / hooks.c
blob4b8ddb84c63108f8b47926903cbcc239ccdb8188
1 /* Ruby scripting hooks */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <ruby.h>
9 #include "elinks.h"
11 #include "cache/cache.h"
12 #include "main/event.h"
13 #include "protocol/uri.h"
14 #include "scripting/ruby/core.h"
15 #include "scripting/ruby/hooks.h"
16 #include "session/location.h"
17 #include "session/session.h"
18 #include "util/string.h"
21 /* The events that will trigger the functions below and what they are expected
22 * to do is explained in doc/events.txt */
24 /* We need to catch and handle errors because, otherwise, Ruby will kill us. */
26 struct erb_protect_info {
27 unsigned char *name;
28 int argc;
29 VALUE *args;
32 static VALUE
33 do_erb_protected_method_call(VALUE data)
35 struct erb_protect_info *info = (struct erb_protect_info *) data;
36 ID method_id;
38 assert(info);
40 method_id = rb_intern(info->name);
42 return rb_funcall3(erb_module, method_id, info->argc, info->args);
45 static VALUE
46 erb_protected_method_call(unsigned char *name, int argc, VALUE *args, int *error)
48 struct erb_protect_info info = { name, argc, args };
50 return rb_protect(do_erb_protected_method_call, (VALUE) &info, error);
55 static enum evhook_status
56 script_hook_goto_url(va_list ap, void *data)
58 unsigned char **url = va_arg(ap, unsigned char **);
59 struct session *ses = va_arg(ap, struct session *);
60 int error;
61 VALUE args[2];
62 VALUE result;
64 if (*url == NULL)
65 return EVENT_HOOK_STATUS_NEXT;
67 args[0] = rb_str_new(*url, strlen(*url));
69 if (!ses || !have_location(ses)) {
70 args[1] = Qnil;
71 } else {
72 args[1] = rb_str_new(struri(cur_loc(ses)->vs.uri), strlen(struri(cur_loc(ses)->vs.uri)));
75 result = erb_protected_method_call("goto_url_hook", 2, args, &error);
76 if (error) {
77 erb_report_error(ses, error);
78 return EVENT_HOOK_STATUS_NEXT;
81 switch (rb_type(result)) {
82 case T_STRING:
84 unsigned char *new_url;
86 new_url = memacpy(RSTRING(result)->ptr, RSTRING(result)->len);
87 if (new_url) {
88 mem_free_set(url, new_url);
90 break;
92 case T_NIL:
93 break;
95 default:
96 alert_ruby_error(ses, "goto_url_hook must return a string or nil");
99 return EVENT_HOOK_STATUS_NEXT;
102 static enum evhook_status
103 script_hook_follow_url(va_list ap, void *data)
105 unsigned char **url = va_arg(ap, unsigned char **);
106 struct session *ses = va_arg(ap, struct session *);
107 int error;
108 VALUE args[1];
109 VALUE result;
111 evhook_use_params(url && ses);
113 if (*url == NULL)
114 return EVENT_HOOK_STATUS_NEXT;
116 args[0] = rb_str_new(*url, strlen(*url));
118 result = erb_protected_method_call("follow_url_hook", 1, args, &error);
119 if (error) {
120 erb_report_error(ses, error);
121 return EVENT_HOOK_STATUS_NEXT;
124 switch (rb_type(result)) {
125 case T_STRING:
127 unsigned char *new_url;
129 new_url = memacpy(RSTRING(result)->ptr, RSTRING(result)->len);
130 if (new_url) {
131 mem_free_set(url, new_url);
133 break;
135 case T_NIL:
136 break;
138 default:
139 alert_ruby_error(ses, "follow_url_hook must return a string or nil");
142 return EVENT_HOOK_STATUS_NEXT;
145 static enum evhook_status
146 script_hook_pre_format_html(va_list ap, void *data)
148 struct session *ses = va_arg(ap, struct session *);
149 struct cache_entry *cached = va_arg(ap, struct cache_entry *);
150 struct fragment *fragment = get_cache_fragment(cached);
151 unsigned char *url = struri(cached->uri);
152 int error;
153 VALUE args[2];
154 VALUE result;
156 evhook_use_params(ses && cached);
158 if (!cached->length || !*fragment->data)
159 return EVENT_HOOK_STATUS_NEXT;
161 args[0] = rb_str_new2(url);
162 args[1] = rb_str_new(fragment->data, fragment->length);
164 result = erb_protected_method_call("pre_format_html_hook", 2, args, &error);
165 if (error) {
166 erb_report_error(ses, error);
167 return EVENT_HOOK_STATUS_NEXT;
170 switch (rb_type(result)) {
171 case T_STRING:
173 int len = RSTRING(result)->len;
175 add_fragment(cached, 0, RSTRING(result)->ptr, len);
176 normalize_cache_entry(cached, len);
178 break;
180 case T_NIL:
181 break;
183 default:
184 alert_ruby_error(ses, "pre_format_html_hook must return a string or nil");
187 return EVENT_HOOK_STATUS_NEXT;
190 /* The Ruby function can return:
191 * - "PROXY:PORT" to use the specified proxy
192 * - "" to not use any proxy
193 * - nil to use the default proxies */
194 static enum evhook_status
195 script_hook_get_proxy(va_list ap, void *data)
197 unsigned char **new_proxy_url = va_arg(ap, unsigned char **);
198 unsigned char *url = va_arg(ap, unsigned char *);
199 int error;
200 VALUE args[1];
201 VALUE result;
203 if (!new_proxy_url || !url)
204 return EVENT_HOOK_STATUS_NEXT;
206 args[0] = rb_str_new(url, strlen(url));
208 result = erb_protected_method_call("proxy_hook", 1, args, &error);
209 if (error) {
210 erb_report_error(NULL, error);
211 return EVENT_HOOK_STATUS_NEXT;
214 switch (rb_type(result)) {
215 case T_STRING:
217 unsigned char *proxy;
219 proxy = memacpy(RSTRING(result)->ptr, RSTRING(result)->len);
220 if (proxy) {
221 mem_free_set(new_proxy_url, proxy);
223 break;
225 case T_NIL:
226 break;
228 default:
229 alert_ruby_error(NULL, "proxy_hook must return a string or nil");
232 return EVENT_HOOK_STATUS_NEXT;
235 static enum evhook_status
236 script_hook_quit(va_list ap, void *data)
238 VALUE args[1];
239 int error;
241 erb_protected_method_call("quit_hook", 0, args, &error);
242 if (error)
243 erb_report_error(NULL, error);
245 return EVENT_HOOK_STATUS_NEXT;
248 struct event_hook_info ruby_scripting_hooks[] = {
249 { "goto-url", 0, script_hook_goto_url, NULL },
250 { "follow-url", 0, script_hook_follow_url, NULL },
251 { "pre-format-html", 0, script_hook_pre_format_html, NULL },
252 { "get-proxy", 0, script_hook_get_proxy, NULL },
253 { "quit", 0, script_hook_quit, NULL },
255 NULL_EVENT_HOOK_INFO,