1 /* Base ECMAScript file. Mostly a proxy for specific library backends. */
11 #include "config/options.h"
12 #include "document/document.h"
13 #include "document/view.h"
14 #include "ecmascript/ecmascript.h"
15 #include "ecmascript/spidermonkey.h"
16 #include "intl/gettext/libintl.h"
17 #include "main/module.h"
18 #include "protocol/uri.h"
19 #include "session/session.h"
20 #include "session/task.h"
21 #include "terminal/terminal.h"
22 #include "terminal/window.h"
23 #include "util/conv.h"
24 #include "viewer/text/view.h" /* current_frame() */
25 #include "viewer/text/form.h" /* <-ecmascript_reset_state() */
26 #include "viewer/text/vs.h"
29 /* TODO: We should have some kind of ACL for the scripts - i.e. ability to
30 * disallow the scripts to open new windows (or so that the windows are always
31 * directed to tabs, this particular option would be a tristate), disallow
32 * messing with your menubar/statusbar visibility, disallow changing the
33 * statusbar content etc. --pasky */
35 static struct option_info ecmascript_options
[] = {
36 INIT_OPT_TREE("", N_("ECMAScript"),
38 N_("ECMAScript options.")),
40 INIT_OPT_BOOL("ecmascript", N_("Enable"),
42 N_("Whether to run those scripts inside of documents.")),
44 INIT_OPT_BOOL("ecmascript", N_("Script error reporting"),
45 "error_reporting", 0, 0,
46 N_("Open a message box when a script reports an error.")),
48 INIT_OPT_BOOL("ecmascript", N_("Ignore <noscript> content"),
49 "ignore_noscript", 0, 0,
50 N_("Whether to ignore content enclosed by the <noscript> tag\n"
51 "when ECMAScript is enabled.")),
53 INIT_OPT_INT("ecmascript", N_("Maximum execution time"),
54 "max_exec_time", 0, 1, 3600, 5,
55 N_("Maximum execution time in seconds for a script.")),
57 INIT_OPT_BOOL("ecmascript", N_("Pop-up window blocking"),
58 "block_window_opening", 0, 0,
59 N_("Whether to disallow scripts to open new windows or tabs.")),
64 #define get_ecmascript_enable() get_opt_bool("ecmascript.enable")
68 ecmascript_init(struct module
*module
)
74 ecmascript_done(struct module
*module
)
80 struct ecmascript_interpreter
*
81 ecmascript_get_interpreter(struct view_state
*vs
)
83 struct ecmascript_interpreter
*interpreter
;
87 interpreter
= mem_calloc(1, sizeof(*interpreter
));
92 init_list(interpreter
->onload_snippets
);
93 spidermonkey_get_interpreter(interpreter
);
99 ecmascript_put_interpreter(struct ecmascript_interpreter
*interpreter
)
102 assert(interpreter
->backend_nesting
== 0);
103 /* If the assertion fails, it is better to leak the
104 * interpreter than to corrupt memory. */
105 if_assert_failed
return;
107 spidermonkey_put_interpreter(interpreter
);
108 free_string_list(&interpreter
->onload_snippets
);
109 mem_free(interpreter
);
113 ecmascript_reset_state(struct view_state
*vs
)
115 struct form_view
*fv
;
118 vs
->ecmascript_fragile
= 0;
120 ecmascript_put_interpreter(vs
->ecmascript
);
122 foreach (fv
, vs
->forms
)
123 fv
->ecmascript_obj
= NULL
;
124 for (i
= 0; i
< vs
->form_info_len
; i
++)
125 vs
->form_info
[i
].ecmascript_obj
= NULL
;
127 vs
->ecmascript
= ecmascript_get_interpreter(vs
);
129 vs
->ecmascript_fragile
= 1;
134 ecmascript_eval(struct ecmascript_interpreter
*interpreter
,
137 if (!get_ecmascript_enable())
140 interpreter
->backend_nesting
++;
141 spidermonkey_eval(interpreter
, code
);
142 interpreter
->backend_nesting
--;
147 ecmascript_eval_stringback(struct ecmascript_interpreter
*interpreter
,
150 unsigned char *result
;
152 if (!get_ecmascript_enable())
155 interpreter
->backend_nesting
++;
156 result
= spidermonkey_eval_stringback(interpreter
, code
);
157 interpreter
->backend_nesting
--;
163 ecmascript_eval_boolback(struct ecmascript_interpreter
*interpreter
,
168 if (!get_ecmascript_enable())
171 interpreter
->backend_nesting
++;
172 result
= spidermonkey_eval_boolback(interpreter
, code
);
173 interpreter
->backend_nesting
--;
179 ecmascript_protocol_handler(struct session
*ses
, struct uri
*uri
)
181 struct document_view
*doc_view
= current_frame(ses
);
182 struct string current_url
= INIT_STRING(struri(uri
), strlen(struri(uri
)));
183 unsigned char *redirect_url
, *redirect_abs_url
;
184 struct uri
*redirect_uri
;
186 if (!doc_view
) /* Blank initial document. TODO: Start at about:blank? */
188 assert(doc_view
->vs
);
189 if (doc_view
->vs
->ecmascript_fragile
)
190 ecmascript_reset_state(doc_view
->vs
);
191 if (!doc_view
->vs
->ecmascript
)
194 redirect_url
= ecmascript_eval_stringback(doc_view
->vs
->ecmascript
,
198 /* XXX: This code snippet is duplicated over here,
199 * location_set_property(), html_a() and who knows where else. */
200 redirect_abs_url
= join_urls(doc_view
->document
->uri
,
201 trim_chars(redirect_url
, ' ', 0));
202 mem_free(redirect_url
);
203 if (!redirect_abs_url
)
205 redirect_uri
= get_uri(redirect_abs_url
, 0);
206 mem_free(redirect_abs_url
);
210 /* XXX: Is that safe to do at this point? --pasky */
211 goto_uri_frame(ses
, redirect_uri
, doc_view
->name
,
213 done_uri(redirect_uri
);
217 struct module ecmascript_module
= struct_module(
218 /* name: */ N_("ECMAScript"),
219 /* options: */ ecmascript_options
,
221 /* submodules: */ NULL
,
223 /* init: */ ecmascript_init
,
224 /* done: */ ecmascript_done