Avoided white on white and similar cases in true color mode.
[elinks.git] / src / ecmascript / ecmascript.c
blob99a63befc8d62fc9d55f26973ada8fe33ac010c3
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/see.h"
16 #include "ecmascript/spidermonkey.h"
17 #include "intl/gettext/libintl.h"
18 #include "main/module.h"
19 #include "osdep/osdep.h"
20 #include "protocol/protocol.h"
21 #include "protocol/uri.h"
22 #include "session/session.h"
23 #include "session/task.h"
24 #include "terminal/terminal.h"
25 #include "terminal/window.h"
26 #include "util/conv.h"
27 #include "util/string.h"
28 #include "viewer/text/view.h" /* current_frame() */
29 #include "viewer/text/form.h" /* <-ecmascript_reset_state() */
30 #include "viewer/text/vs.h"
33 /* TODO: We should have some kind of ACL for the scripts - i.e. ability to
34 * disallow the scripts to open new windows (or so that the windows are always
35 * directed to tabs, this particular option would be a tristate), disallow
36 * messing with your menubar/statusbar visibility, disallow changing the
37 * statusbar content etc. --pasky */
39 static struct option_info ecmascript_options[] = {
40 INIT_OPT_TREE("", N_("ECMAScript"),
41 "ecmascript", 0,
42 N_("ECMAScript options.")),
44 INIT_OPT_BOOL("ecmascript", N_("Enable"),
45 "enable", 0, 1,
46 N_("Whether to run those scripts inside of documents.")),
48 INIT_OPT_BOOL("ecmascript", N_("Script error reporting"),
49 "error_reporting", 0, 0,
50 N_("Open a message box when a script reports an error.")),
52 INIT_OPT_BOOL("ecmascript", N_("Ignore <noscript> content"),
53 "ignore_noscript", 0, 0,
54 N_("Whether to ignore content enclosed by the <noscript> tag\n"
55 "when ECMAScript is enabled.")),
57 INIT_OPT_INT("ecmascript", N_("Maximum execution time"),
58 "max_exec_time", 0, 1, 3600, 5,
59 N_("Maximum execution time in seconds for a script.")),
61 INIT_OPT_BOOL("ecmascript", N_("Pop-up window blocking"),
62 "block_window_opening", 0, 0,
63 N_("Whether to disallow scripts to open new windows or tabs.")),
65 NULL_OPTION_INFO,
68 #define NUMBER_OF_URLS_TO_REMEMBER 8
69 static struct {
70 unsigned char *url;
71 unsigned char *frame;
72 } u[NUMBER_OF_URLS_TO_REMEMBER];
73 static int url_index = 0;
75 int
76 ecmascript_check_url(unsigned char *url, unsigned char *frame)
78 int i;
79 /* Because of gradual rendering window.open is called many
80 * times with the same arguments.
81 * This workaround remembers NUMBER_OF_URLS_TO_REMEMBER last
82 * opened URLs and do not let open them again.
85 for (i = 0; i < NUMBER_OF_URLS_TO_REMEMBER; i++) {
86 if (!u[i].url) break;
87 if (!strcmp(u[i].url, url) && !strcmp(u[i].frame, frame)) {
88 mem_free(url);
89 mem_free(frame);
90 return 0;
93 mem_free_if(u[url_index].url);
94 mem_free_if(u[url_index].frame);
95 u[url_index].url = url;
96 u[url_index].frame = frame;
97 url_index++;
98 if (url_index >= NUMBER_OF_URLS_TO_REMEMBER) url_index = 0;
99 return 1;
102 void
103 ecmascript_free_urls(struct module *module)
105 int i;
107 for (i = 0; i < NUMBER_OF_URLS_TO_REMEMBER; i++) {
108 mem_free_if(u[i].url);
109 mem_free_if(u[i].frame);
113 #undef NUMBER_OF_URLS_TO_REMEMBER
115 struct ecmascript_interpreter *
116 ecmascript_get_interpreter(struct view_state *vs)
118 struct ecmascript_interpreter *interpreter;
120 assert(vs);
122 interpreter = mem_calloc(1, sizeof(*interpreter));
123 if (!interpreter)
124 return NULL;
126 interpreter->vs = vs;
127 init_list(interpreter->onload_snippets);
128 #ifdef CONFIG_ECMASCRIPT_SEE
129 see_get_interpreter(interpreter);
130 #else
131 spidermonkey_get_interpreter(interpreter);
132 #endif
133 return interpreter;
136 void
137 ecmascript_put_interpreter(struct ecmascript_interpreter *interpreter)
139 assert(interpreter);
140 #ifdef CONFIG_ECMASCRIPT_SEE
141 see_put_interpreter(interpreter);
142 #else
143 spidermonkey_put_interpreter(interpreter);
144 #endif
145 free_string_list(&interpreter->onload_snippets);
146 interpreter->vs->ecmascript = NULL;
147 mem_free(interpreter);
150 void
151 ecmascript_eval(struct ecmascript_interpreter *interpreter,
152 struct string *code, struct string *ret)
154 if (!get_ecmascript_enable())
155 return;
156 assert(interpreter);
157 #ifdef CONFIG_ECMASCRIPT_SEE
158 see_eval(interpreter, code, ret);
159 #else
160 spidermonkey_eval(interpreter, code, ret);
161 #endif
164 unsigned char *
165 ecmascript_eval_stringback(struct ecmascript_interpreter *interpreter,
166 struct string *code)
168 if (!get_ecmascript_enable())
169 return NULL;
170 assert(interpreter);
171 #ifdef CONFIG_ECMASCRIPT_SEE
172 return see_eval_stringback(interpreter, code);
173 #else
174 return spidermonkey_eval_stringback(interpreter, code);
175 #endif
179 ecmascript_eval_boolback(struct ecmascript_interpreter *interpreter,
180 struct string *code)
182 if (!get_ecmascript_enable())
183 return -1;
184 assert(interpreter);
185 #ifdef CONFIG_ECMASCRIPT_SEE
186 return see_eval_boolback(interpreter, code);
187 #else
188 return spidermonkey_eval_boolback(interpreter, code);
189 #endif
193 void
194 ecmascript_reset_state(struct view_state *vs)
196 struct form_view *fv;
197 int i;
199 vs->ecmascript_fragile = 0;
200 if (vs->ecmascript)
201 ecmascript_put_interpreter(vs->ecmascript);
203 foreach (fv, vs->forms)
204 fv->ecmascript_obj = NULL;
205 for (i = 0; i < vs->form_info_len; i++)
206 vs->form_info[i].ecmascript_obj = NULL;
208 vs->ecmascript = ecmascript_get_interpreter(vs);
209 if (!vs->ecmascript)
210 vs->ecmascript_fragile = 1;
213 void
214 ecmascript_protocol_handler(struct session *ses, struct uri *uri)
216 struct document_view *doc_view = current_frame(ses);
217 struct string current_url = INIT_STRING(struri(uri), strlen(struri(uri)));
218 unsigned char *redirect_url, *redirect_abs_url;
219 struct uri *redirect_uri;
221 if (!doc_view) /* Blank initial document. TODO: Start at about:blank? */
222 return;
223 assert(doc_view->vs);
224 if (doc_view->vs->ecmascript_fragile)
225 ecmascript_reset_state(doc_view->vs);
226 if (!doc_view->vs->ecmascript)
227 return;
229 redirect_url = ecmascript_eval_stringback(doc_view->vs->ecmascript,
230 &current_url);
231 if (!redirect_url)
232 return;
233 /* XXX: This code snippet is duplicated over here,
234 * location_set_property(), html_a() and who knows where else. */
235 redirect_abs_url = join_urls(doc_view->document->uri,
236 trim_chars(redirect_url, ' ', 0));
237 mem_free(redirect_url);
238 if (!redirect_abs_url)
239 return;
240 redirect_uri = get_uri(redirect_abs_url, 0);
241 mem_free(redirect_abs_url);
242 if (!redirect_uri)
243 return;
245 /* XXX: Is that safe to do at this point? --pasky */
246 goto_uri_frame(ses, redirect_uri, doc_view->name,
247 CACHE_MODE_NORMAL);
248 done_uri(redirect_uri);
252 void
253 ecmascript_timeout_dialog(struct terminal *term, int max_exec_time)
255 info_box(term, MSGBOX_FREE_TEXT,
256 N_("JavaScript Emergency"), ALIGN_LEFT,
257 msg_text(term,
258 N_("A script embedded in the current document was running\n"
259 "for more than %d seconds. This probably means there is\n"
260 "a bug in the script and it could have halted the whole\n"
261 "ELinks, so the script execution was interrupted."),
262 max_exec_time));
266 void
267 ecmascript_set_action(unsigned char **action, unsigned char *string)
269 struct uri *protocol;
271 trim_chars(string, ' ', NULL);
272 protocol = get_uri(string, URI_PROTOCOL);
274 if (protocol) { /* full uri with protocol */
275 done_uri(protocol);
276 mem_free_set(action, string);
277 } else {
278 if (dir_sep(string[0])) { /* absolute uri, TODO: disk drive under WIN32 */
279 struct uri *uri = get_uri(*action, URI_HTTP_REFERRER_HOST);
281 if (uri->protocol == PROTOCOL_FILE) {
282 mem_free_set(action, straconcat(struri(uri), string, NULL));
284 else
285 mem_free_set(action, straconcat(struri(uri), string + 1, NULL));
286 done_uri(uri);
287 mem_free(string);
288 } else { /* relative uri */
289 unsigned char *last_slash = strrchr(*action, '/');
290 unsigned char *new_action;
292 if (last_slash) *(last_slash + 1) = '\0';
293 new_action = straconcat(*action, string, NULL);
294 mem_free_set(action, new_action);
295 mem_free(string);
300 static struct module *ecmascript_modules[] = {
301 #ifdef CONFIG_ECMASCRIPT_SEE
302 &see_module,
303 #elif defined(CONFIG_ECMASCRIPT_SMJS)
304 &spidermonkey_module,
305 #endif
306 NULL,
310 struct module ecmascript_module = struct_module(
311 /* name: */ N_("ECMAScript"),
312 /* options: */ ecmascript_options,
313 /* events: */ NULL,
314 /* submodules: */ ecmascript_modules,
315 /* data: */ NULL,
316 /* init: */ NULL,
317 /* done: */ ecmascript_free_urls