grafthistory: support curl
[elinks/elinks-j605.git] / src / ecmascript / ecmascript.c
blobfb513d12c64ec80ca9b4eae6a3b4a0d142348140
1 /* Base ECMAScript file. Mostly a proxy for specific library backends. */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <stdlib.h>
9 #include "elinks.h"
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"),
37 "ecmascript", 0,
38 N_("ECMAScript options.")),
40 INIT_OPT_BOOL("ecmascript", N_("Enable"),
41 "enable", 0, 1,
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.")),
61 NULL_OPTION_INFO,
64 #define get_ecmascript_enable() get_opt_bool("ecmascript.enable")
67 static void
68 ecmascript_init(struct module *module)
70 spidermonkey_init();
73 static void
74 ecmascript_done(struct module *module)
76 spidermonkey_done();
80 struct ecmascript_interpreter *
81 ecmascript_get_interpreter(struct view_state *vs)
83 struct ecmascript_interpreter *interpreter;
85 assert(vs);
87 interpreter = mem_calloc(1, sizeof(*interpreter));
88 if (!interpreter)
89 return NULL;
91 interpreter->vs = vs;
92 init_list(interpreter->onload_snippets);
93 spidermonkey_get_interpreter(interpreter);
95 return interpreter;
98 void
99 ecmascript_put_interpreter(struct ecmascript_interpreter *interpreter)
101 assert(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);
112 void
113 ecmascript_reset_state(struct view_state *vs)
115 struct form_view *fv;
116 int i;
118 vs->ecmascript_fragile = 0;
119 if (vs->ecmascript)
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);
128 if (!vs->ecmascript)
129 vs->ecmascript_fragile = 1;
133 void
134 ecmascript_eval(struct ecmascript_interpreter *interpreter,
135 struct string *code)
137 if (!get_ecmascript_enable())
138 return;
139 assert(interpreter);
140 interpreter->backend_nesting++;
141 spidermonkey_eval(interpreter, code);
142 interpreter->backend_nesting--;
146 unsigned char *
147 ecmascript_eval_stringback(struct ecmascript_interpreter *interpreter,
148 struct string *code)
150 unsigned char *result;
152 if (!get_ecmascript_enable())
153 return NULL;
154 assert(interpreter);
155 interpreter->backend_nesting++;
156 result = spidermonkey_eval_stringback(interpreter, code);
157 interpreter->backend_nesting--;
158 return result;
163 ecmascript_eval_boolback(struct ecmascript_interpreter *interpreter,
164 struct string *code)
166 int result;
168 if (!get_ecmascript_enable())
169 return -1;
170 assert(interpreter);
171 interpreter->backend_nesting++;
172 result = spidermonkey_eval_boolback(interpreter, code);
173 interpreter->backend_nesting--;
174 return result;
178 void
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? */
187 return;
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)
192 return;
194 redirect_url = ecmascript_eval_stringback(doc_view->vs->ecmascript,
195 &current_url);
196 if (!redirect_url)
197 return;
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)
204 return;
205 redirect_uri = get_uri(redirect_abs_url, 0);
206 mem_free(redirect_abs_url);
207 if (!redirect_uri)
208 return;
210 /* XXX: Is that safe to do at this point? --pasky */
211 goto_uri_frame(ses, redirect_uri, doc_view->name,
212 CACHE_MODE_NORMAL);
213 done_uri(redirect_uri);
217 struct module ecmascript_module = struct_module(
218 /* name: */ N_("ECMAScript"),
219 /* options: */ ecmascript_options,
220 /* events: */ NULL,
221 /* submodules: */ NULL,
222 /* data: */ NULL,
223 /* init: */ ecmascript_init,
224 /* done: */ ecmascript_done