ECMAScript: added writeonly property window.status
[elinks.git] / src / ecmascript / see / window.c
blob361be6ea55992000b4a928a51008a3a95a9535e3
1 /* The SEE window object implementation. */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <time.h>
12 #include "elinks.h"
14 #include <see/see.h>
16 #include "bfu/dialog.h"
17 #include "cache/cache.h"
18 #include "cookies/cookies.h"
19 #include "dialogs/menu.h"
20 #include "dialogs/status.h"
21 #include "document/html/frames.h"
22 #include "document/document.h"
23 #include "document/forms.h"
24 #include "document/view.h"
25 #include "ecmascript/ecmascript.h"
26 #include "ecmascript/see/input.h"
27 #include "ecmascript/see/strings.h"
28 #include "ecmascript/see/window.h"
29 #include "intl/gettext/libintl.h"
30 #include "main/select.h"
31 #include "osdep/newwin.h"
32 #include "osdep/sysname.h"
33 #include "protocol/http/http.h"
34 #include "protocol/uri.h"
35 #include "session/history.h"
36 #include "session/location.h"
37 #include "session/session.h"
38 #include "session/task.h"
39 #include "terminal/tab.h"
40 #include "terminal/terminal.h"
41 #include "util/conv.h"
42 #include "util/memory.h"
43 #include "util/string.h"
44 #include "viewer/text/draw.h"
45 #include "viewer/text/form.h"
46 #include "viewer/text/link.h"
47 #include "viewer/text/vs.h"
49 static struct js_window_object *js_get_global_object(void *);
50 static struct js_window_object *js_try_resolve_frame(struct document_view *, unsigned char *);
51 static void window_get(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *);
52 static void window_put(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *, int);
53 static int window_canput(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *);
54 static int window_hasproperty(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *);
55 static void js_window_alert(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
56 static void js_window_open(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
57 static void js_setTimeout(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
59 void location_goto(struct document_view *, unsigned char *);
61 struct SEE_objectclass js_window_object_class = {
62 "window",
63 window_get,
64 window_put,
65 window_canput,
66 window_hasproperty,
67 SEE_no_delete,
68 SEE_no_defaultvalue,
69 NULL,
70 NULL,
71 NULL,
72 NULL
75 static struct js_window_object *
76 js_get_global_object(void *data)
78 struct global_object *g = (struct global_object *)data;
79 return g->win;
82 static struct js_window_object *
83 js_try_resolve_frame(struct document_view *doc_view, unsigned char *id)
85 struct session *ses = doc_view->session;
86 struct frame *target;
88 assert(ses);
89 target = ses_find_frame(ses, id);
90 if (!target) return NULL;
91 if (target->vs.ecmascript_fragile)
92 ecmascript_reset_state(&target->vs);
93 if (!target->vs.ecmascript) return NULL;
94 return js_get_global_object(target->vs.ecmascript->backend_data);
97 static void
98 window_get(struct SEE_interpreter *interp, struct SEE_object *o,
99 struct SEE_string *p, struct SEE_value *res)
101 struct js_window_object *win = (struct js_window_object *)o;
102 struct view_state *vs = win->vs;
104 if (p == s_closed) {
105 SEE_SET_BOOLEAN(res, 0);
106 } else if (p == s_self || p == s_parent || p == s_top || p == s_status) {
107 SEE_SET_OBJECT(res, o);
108 #if 0
109 } else if (p == s_parent || p == s_top) {
110 struct document_view *doc_view = vs->doc_view;
111 struct document_view *top_view = doc_view->session->doc_view;
112 struct js_window_object *newjsframe;
114 assert(top_view && top_view->vs);
115 if (top_view->vs->ecmascript_fragile)
116 ecmascript_reset_state(top_view->vs);
117 if (!top_view->vs->ecmascript) {
118 SEE_SET_UNDEFINED(res);
119 return;
121 newjsframe = js_get_global_object(
122 top_view->vs->ecmascript->backend_data);
124 /* Keep this unrolled this way. Will have to check document.domain
125 * JS property. */
126 /* Note that this check is perhaps overparanoid. If top windows
127 * is alien but some other child window is not, we should still
128 * let the script walk thru. That'd mean moving the check to
129 * other individual properties in this switch. */
130 if (compare_uri(vs->uri, top_view->vs->uri, URI_HOST)) {
131 SEE_SET_OBJECT(res, (struct SEE_object *)newjsframe);
133 #endif
134 } else if (p == s_alert) {
135 SEE_SET_OBJECT(res, win->alert);
136 } else if (p == s_open) {
137 SEE_SET_OBJECT(res, win->open);
138 } else if (p == s_setTimeout) {
139 SEE_SET_OBJECT(res, win->setTimeout);
140 } else if (p == s_location) {
141 SEE_OBJECT_GET(interp, interp->Global, s_location, res);
142 } else if (p == s_navigator) {
143 SEE_OBJECT_GET(interp, interp->Global, s_navigator, res);
144 } else {
145 unsigned char *frame = SEE_string_to_unsigned_char(p);
146 struct document_view *doc_view = vs->doc_view;
147 struct js_window_object *obj;
149 if (frame && (obj = js_try_resolve_frame(doc_view, frame))) {
150 SEE_SET_OBJECT(res, (struct SEE_object *)obj);
151 } else {
152 SEE_SET_UNDEFINED(res);
154 mem_free_if(frame);
158 static void
159 window_put(struct SEE_interpreter *interp, struct SEE_object *o,
160 struct SEE_string *p, struct SEE_value *val, int attr)
162 if (p == s_location) {
163 struct js_window_object *win = (struct js_window_object *)o;
164 struct view_state *vs = win->vs;
165 struct document_view *doc_view = vs->doc_view;
166 unsigned char *str = SEE_value_to_unsigned_char(interp, val);
168 if (str) {
169 location_goto(doc_view, str);
170 mem_free(str);
172 } else if (p == s_status) {
173 struct global_object *g = (struct global_object *)interp;
174 struct js_window_object *win = g->win;
175 struct view_state *vs = win->vs;
176 struct document_view *doc_view = vs->doc_view;
177 struct session *ses = doc_view->session;
178 unsigned char *stat = SEE_value_to_unsigned_char(interp, val);
180 mem_free_set(&ses->status.window_status, stat);
181 print_screen_status(ses);
185 static int
186 window_canput(struct SEE_interpreter *interp, struct SEE_object *o,
187 struct SEE_string *p)
189 if (p == s_location || p == s_status)
190 return 1;
191 return 0;
194 static int
195 window_hasproperty(struct SEE_interpreter *interp, struct SEE_object *o,
196 struct SEE_string *p)
198 /* all unknown properties return UNDEFINED value */
199 return 1;
203 static void
204 js_window_alert(struct SEE_interpreter *interp, struct SEE_object *self,
205 struct SEE_object *thisobj, int argc, struct SEE_value **argv,
206 struct SEE_value *res)
208 struct global_object *g = (struct global_object *)interp;
209 struct js_window_object *win = g->win;
210 struct view_state *vs = win->vs;
211 unsigned char *string;
213 SEE_SET_BOOLEAN(res, 1);
214 if (argc < 1)
215 return;
217 string = SEE_value_to_unsigned_char(interp, argv[0]);
218 if (!string || !*string) {
219 mem_free_if(string);
220 return;
223 info_box(vs->doc_view->session->tab->term, MSGBOX_FREE_TEXT,
224 N_("JavaScript Alert"), ALIGN_CENTER, string);
229 static void
230 js_window_open(struct SEE_interpreter *interp, struct SEE_object *self,
231 struct SEE_object *thisobj, int argc, struct SEE_value **argv,
232 struct SEE_value *res)
234 struct global_object *g = (struct global_object *)interp;
235 struct js_window_object *win = g->win;
236 struct view_state *vs = win->vs;
237 struct document_view *doc_view = vs->doc_view;
238 struct session *ses = doc_view->session;
239 unsigned char *frame = "";
240 unsigned char *url;
241 struct uri *uri;
242 struct SEE_value url_value;
243 #if 0
244 static time_t ratelimit_start;
245 static int ratelimit_count;
246 #endif
247 SEE_SET_OBJECT(res, (struct SEE_object *)win);
248 if (get_opt_bool("ecmascript.block_window_opening")) {
249 #ifdef CONFIG_LEDS
250 set_led_value(ses->status.popup_led, 'P');
251 #endif
252 return;
255 if (argc < 1) return;
256 #if 0
257 /* Ratelimit window opening. Recursive window.open() is very nice.
258 * We permit at most 20 tabs in 2 seconds. The ratelimiter is very
259 * rough but shall suffice against the usual cases. */
261 if (!ratelimit_start || time(NULL) - ratelimit_start > 2) {
262 ratelimit_start = time(NULL);
263 ratelimit_count = 0;
264 } else {
265 ratelimit_count++;
266 if (ratelimit_count > 20)
267 return;
269 #endif
270 SEE_ToString(interp, argv[0], &url_value);
271 url = SEE_string_to_unsigned_char(url_value.u.string);
272 if (!url) return;
273 trim_chars(url, ' ', 0);
274 if (argc > 1) {
275 struct SEE_value target_value;
277 SEE_ToString(interp, argv[1], &target_value);
278 frame = SEE_string_to_unsigned_char(target_value.u.string);
279 if (!frame) {
280 mem_free(url);
281 return;
283 /* url and frame will be freed by ecmascript_check_url */
284 if (!ecmascript_check_url(url, frame)) return;
286 /* TODO: Support for window naming and perhaps some window features? */
288 url = join_urls(doc_view->document->uri, url);
289 if (!url) return;
290 uri = get_uri(url, 0);
291 mem_free(url);
292 if (!uri) return;
294 if (*frame && strcasecmp(frame, "_blank")) {
295 struct delayed_open *deo = mem_calloc(1, sizeof(*deo));
297 if (deo) {
298 deo->ses = ses;
299 deo->uri = get_uri_reference(uri);
300 deo->target = stracpy(frame);
301 /* target will be freed in delayed_goto_uri_frame */
302 register_bottom_half(delayed_goto_uri_frame, deo);
303 goto end;
307 if (!get_cmd_opt_bool("no-connect")
308 && !get_cmd_opt_bool("no-home")
309 && !get_cmd_opt_bool("anonymous")
310 && can_open_in_new(ses->tab->term)) {
311 open_uri_in_new_window(ses, uri, NULL, ENV_ANY,
312 CACHE_MODE_NORMAL, TASK_NONE);
313 } else {
314 /* When opening a new tab, we might get rerendered, losing our
315 * context and triggerring a disaster, so postpone that. */
316 struct delayed_open *deo = mem_calloc(1, sizeof(*deo));
318 if (deo) {
319 deo->ses = ses;
320 deo->uri = get_uri_reference(uri);
321 register_bottom_half(delayed_open, deo);
325 end:
326 done_uri(uri);
329 static void
330 js_setTimeout(struct SEE_interpreter *interp, struct SEE_object *self,
331 struct SEE_object *thisobj, int argc, struct SEE_value **argv,
332 struct SEE_value *res)
334 struct ecmascript_interpreter *ei;
335 unsigned char *code;
336 int timeout;
338 if (argc != 2) return;
339 ei = ((struct global_object *)interp)->interpreter;
340 code = SEE_value_to_unsigned_char(interp, argv[0]);
341 timeout = SEE_ToInt32(interp, argv[1]);
342 ecmascript_set_timeout(ei, code, timeout);
345 void
346 init_js_window_object(struct ecmascript_interpreter *interpreter)
348 struct global_object *g = interpreter->backend_data;
349 struct SEE_interpreter *interp = &g->interp;
350 struct SEE_value v;
352 g->win = SEE_NEW(interp, struct js_window_object);
354 g->win->object.objectclass = &js_window_object_class;
355 g->win->object.Prototype = NULL;
356 g->win->vs = interpreter->vs;
358 SEE_SET_OBJECT(&v, (struct SEE_object *)g->win);
359 SEE_OBJECT_PUT(interp, interp->Global, s_window, &v, 0);
361 g->win->alert = SEE_cfunction_make(interp, js_window_alert, s_alert, 1);
362 g->win->open = SEE_cfunction_make(interp, js_window_open, s_open, 3);
363 g->win->setTimeout = SEE_cfunction_make(interp, js_setTimeout, s_setTimeout, 2);
365 SEE_OBJECT_GET(interp, (struct SEE_object *)g->win, s_top, &v);
366 SEE_OBJECT_PUT(interp, interp->Global, s_top, &v, 0);
368 SEE_OBJECT_GET(interp, (struct SEE_object *)g->win, s_self, &v);
369 SEE_OBJECT_PUT(interp, interp->Global, s_self, &v, 0);
371 SEE_OBJECT_GET(interp, (struct SEE_object *)g->win, s_alert, &v);
372 SEE_OBJECT_PUT(interp, interp->Global, s_alert, &v, 0);
373 SEE_OBJECT_GET(interp, (struct SEE_object *)g->win, s_open, &v);
374 SEE_OBJECT_PUT(interp, interp->Global, s_open, &v, 0);
375 SEE_OBJECT_GET(interp, (struct SEE_object *)g->win, s_setTimeout, &v);
376 SEE_OBJECT_PUT(interp, interp->Global, s_setTimeout, &v, 0);
379 void
380 checktime(struct SEE_interpreter *interp)
382 struct global_object *g = (struct global_object *)interp;
384 if (time(NULL) - g->exec_start > g->max_exec_time) {
385 struct terminal *term = g->win->vs->doc_view->session->tab->term;
386 /* A killer script! Alert! */
387 ecmascript_timeout_dialog(term, g->max_exec_time);
388 SEE_error_throw_string(interp, interp->Error, s_timeout);