1 /* Ruby scripting hooks */
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
{
33 do_erb_protected_method_call(VALUE data
)
35 struct erb_protect_info
*info
= (struct erb_protect_info
*) data
;
40 method_id
= rb_intern(info
->name
);
42 return rb_funcall3(erb_module
, method_id
, info
->argc
, info
->args
);
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
*);
65 return EVENT_HOOK_STATUS_NEXT
;
67 args
[0] = rb_str_new(*url
, strlen(*url
));
69 if (!ses
|| !have_location(ses
)) {
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
);
77 erb_report_error(ses
, error
);
78 return EVENT_HOOK_STATUS_NEXT
;
81 switch (rb_type(result
)) {
84 unsigned char *new_url
;
86 new_url
= memacpy(RSTRING(result
)->ptr
, RSTRING(result
)->len
);
88 mem_free_set(url
, new_url
);
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
*);
111 evhook_use_params(url
&& ses
);
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
);
120 erb_report_error(ses
, error
);
121 return EVENT_HOOK_STATUS_NEXT
;
124 switch (rb_type(result
)) {
127 unsigned char *new_url
;
129 new_url
= memacpy(RSTRING(result
)->ptr
, RSTRING(result
)->len
);
131 mem_free_set(url
, new_url
);
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
);
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
);
166 erb_report_error(ses
, error
);
167 return EVENT_HOOK_STATUS_NEXT
;
170 switch (rb_type(result
)) {
173 int len
= RSTRING(result
)->len
;
175 add_fragment(cached
, 0, RSTRING(result
)->ptr
, len
);
176 normalize_cache_entry(cached
, len
);
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 *);
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
);
210 erb_report_error(NULL
, error
);
211 return EVENT_HOOK_STATUS_NEXT
;
214 switch (rb_type(result
)) {
217 unsigned char *proxy
;
219 proxy
= memacpy(RSTRING(result
)->ptr
, RSTRING(result
)->len
);
221 mem_free_set(new_proxy_url
, proxy
);
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
)
241 erb_protected_method_call("quit_hook", 0, args
, &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
,