1 /* The SEE window object implementation. */
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/checktype.h"
27 #include "ecmascript/see/input.h"
28 #include "ecmascript/see/strings.h"
29 #include "ecmascript/see/window.h"
30 #include "intl/gettext/libintl.h"
31 #include "main/select.h"
32 #include "osdep/newwin.h"
33 #include "osdep/sysname.h"
34 #include "protocol/http/http.h"
35 #include "protocol/uri.h"
36 #include "session/history.h"
37 #include "session/location.h"
38 #include "session/session.h"
39 #include "session/task.h"
40 #include "terminal/tab.h"
41 #include "terminal/terminal.h"
42 #include "util/conv.h"
43 #include "util/memory.h"
44 #include "util/string.h"
45 #include "viewer/text/draw.h"
46 #include "viewer/text/form.h"
47 #include "viewer/text/link.h"
48 #include "viewer/text/vs.h"
50 static struct js_window_object
*js_get_global_object(void *);
51 static struct js_window_object
*js_try_resolve_frame(struct document_view
*, unsigned char *);
52 static void window_get(struct SEE_interpreter
*, struct SEE_object
*, struct SEE_string
*, struct SEE_value
*);
53 static void window_put(struct SEE_interpreter
*, struct SEE_object
*, struct SEE_string
*, struct SEE_value
*, int);
54 static int window_canput(struct SEE_interpreter
*, struct SEE_object
*, struct SEE_string
*);
55 static int window_hasproperty(struct SEE_interpreter
*, struct SEE_object
*, struct SEE_string
*);
56 static void js_window_alert(struct SEE_interpreter
*, struct SEE_object
*, struct SEE_object
*, int, struct SEE_value
**, struct SEE_value
*);
57 static void js_window_open(struct SEE_interpreter
*, struct SEE_object
*, struct SEE_object
*, int, struct SEE_value
**, struct SEE_value
*);
58 static void js_setTimeout(struct SEE_interpreter
*, struct SEE_object
*, struct SEE_object
*, int, struct SEE_value
**, struct SEE_value
*);
60 struct SEE_objectclass js_window_object_class
= {
74 static struct js_window_object
*
75 js_get_global_object(void *data
)
77 struct global_object
*g
= (struct global_object
*)data
;
81 static struct js_window_object
*
82 js_try_resolve_frame(struct document_view
*doc_view
, unsigned char *id
)
84 struct session
*ses
= doc_view
->session
;
88 target
= ses_find_frame(ses
, id
);
89 if (!target
) return NULL
;
90 if (target
->vs
.ecmascript_fragile
)
91 ecmascript_reset_state(&target
->vs
);
92 if (!target
->vs
.ecmascript
) return NULL
;
93 return js_get_global_object(target
->vs
.ecmascript
->backend_data
);
97 window_get(struct SEE_interpreter
*interp
, struct SEE_object
*o
,
98 struct SEE_string
*p
, struct SEE_value
*res
)
100 struct js_window_object
*win
= (struct js_window_object
*)o
;
101 struct view_state
*vs
= win
->vs
;
104 SEE_SET_BOOLEAN(res
, 0);
105 } else if (p
== s_self
|| p
== s_parent
|| p
== s_top
|| p
== s_status
) {
106 SEE_SET_OBJECT(res
, o
);
108 } else if (p
== s_parent
|| p
== s_top
) {
109 struct document_view
*doc_view
= vs
->doc_view
;
110 struct document_view
*top_view
= doc_view
->session
->doc_view
;
111 struct js_window_object
*newjsframe
;
113 assert(top_view
&& top_view
->vs
);
114 if (top_view
->vs
->ecmascript_fragile
)
115 ecmascript_reset_state(top_view
->vs
);
116 if (!top_view
->vs
->ecmascript
) {
117 SEE_SET_UNDEFINED(res
);
120 newjsframe
= js_get_global_object(
121 top_view
->vs
->ecmascript
->backend_data
);
123 /* Keep this unrolled this way. Will have to check document.domain
125 /* Note that this check is perhaps overparanoid. If top windows
126 * is alien but some other child window is not, we should still
127 * let the script walk thru. That'd mean moving the check to
128 * other individual properties in this switch. */
129 if (compare_uri(vs
->uri
, top_view
->vs
->uri
, URI_HOST
)) {
130 SEE_SET_OBJECT(res
, (struct SEE_object
*)newjsframe
);
133 } else if (p
== s_alert
) {
134 SEE_SET_OBJECT(res
, win
->alert
);
135 } else if (p
== s_open
) {
136 SEE_SET_OBJECT(res
, win
->open
);
137 } else if (p
== s_setTimeout
) {
138 SEE_SET_OBJECT(res
, win
->setTimeout
);
139 } else if (p
== s_location
) {
140 SEE_OBJECT_GET(interp
, interp
->Global
, s_location
, res
);
141 } else if (p
== s_navigator
) {
142 SEE_OBJECT_GET(interp
, interp
->Global
, s_navigator
, res
);
144 unsigned char *frame
= see_string_to_unsigned_char(p
);
145 struct document_view
*doc_view
= vs
->doc_view
;
146 struct js_window_object
*obj
;
148 if (frame
&& (obj
= js_try_resolve_frame(doc_view
, frame
))) {
149 SEE_SET_OBJECT(res
, (struct SEE_object
*)obj
);
151 SEE_SET_UNDEFINED(res
);
158 window_put(struct SEE_interpreter
*interp
, struct SEE_object
*o
,
159 struct SEE_string
*p
, struct SEE_value
*val
, int attr
)
161 if (p
== s_location
) {
162 struct js_window_object
*win
= (struct js_window_object
*)o
;
163 struct view_state
*vs
= win
->vs
;
164 struct document_view
*doc_view
= vs
->doc_view
;
165 unsigned char *str
= see_value_to_unsigned_char(interp
, val
);
168 location_goto(doc_view
, str
);
171 } else if (p
== s_status
) {
172 struct global_object
*g
= (struct global_object
*)interp
;
173 struct js_window_object
*win
= g
->win
;
174 struct view_state
*vs
= win
->vs
;
175 struct document_view
*doc_view
= vs
->doc_view
;
176 struct session
*ses
= doc_view
->session
;
177 unsigned char *stat
= see_value_to_unsigned_char(interp
, val
);
179 mem_free_set(&ses
->status
.window_status
, stat
);
180 print_screen_status(ses
);
185 window_canput(struct SEE_interpreter
*interp
, struct SEE_object
*o
,
186 struct SEE_string
*p
)
188 if (p
== s_location
|| p
== s_status
)
194 window_hasproperty(struct SEE_interpreter
*interp
, struct SEE_object
*o
,
195 struct SEE_string
*p
)
197 /* all unknown properties return UNDEFINED value */
203 js_window_alert(struct SEE_interpreter
*interp
, struct SEE_object
*self
,
204 struct SEE_object
*thisobj
, int argc
, struct SEE_value
**argv
,
205 struct SEE_value
*res
)
207 struct global_object
*g
= (struct global_object
*)interp
;
208 struct js_window_object
*win
= g
->win
;
209 struct view_state
*vs
= win
->vs
;
210 unsigned char *string
;
212 /* Do not check thisobj->objectclass. ELinks sets this
213 * function as a property of both the window object and the
214 * global object, so thisobj may validly refer to either. */
216 SEE_SET_BOOLEAN(res
, 1);
220 string
= see_value_to_unsigned_char(interp
, argv
[0]);
221 if (!string
|| !*string
) {
226 info_box(vs
->doc_view
->session
->tab
->term
, MSGBOX_FREE_TEXT
,
227 N_("JavaScript Alert"), ALIGN_CENTER
, string
);
233 js_window_open(struct SEE_interpreter
*interp
, struct SEE_object
*self
,
234 struct SEE_object
*thisobj
, int argc
, struct SEE_value
**argv
,
235 struct SEE_value
*res
)
237 struct global_object
*g
= (struct global_object
*)interp
;
238 struct js_window_object
*win
= g
->win
;
239 struct view_state
*vs
= win
->vs
;
240 struct document_view
*doc_view
= vs
->doc_view
;
241 struct session
*ses
= doc_view
->session
;
242 unsigned char *frame
= NULL
;
243 unsigned char *url
, *url2
;
245 struct SEE_value url_value
;
246 static time_t ratelimit_start
;
247 static int ratelimit_count
;
249 /* Do not check thisobj->objectclass. ELinks sets this
250 * function as a property of both the window object and the
251 * global object, so thisobj may validly refer to either. */
253 SEE_SET_OBJECT(res
, (struct SEE_object
*)win
);
254 if (get_opt_bool("ecmascript.block_window_opening")) {
256 set_led_value(ses
->status
.popup_led
, 'P');
261 if (argc
< 1) return;
263 /* Ratelimit window opening. Recursive window.open() is very nice.
264 * We permit at most 20 tabs in 2 seconds. The ratelimiter is very
265 * rough but shall suffice against the usual cases. */
267 if (!ratelimit_start
|| time(NULL
) - ratelimit_start
> 2) {
268 ratelimit_start
= time(NULL
);
272 if (ratelimit_count
> 20)
276 SEE_ToString(interp
, argv
[0], &url_value
);
277 url
= see_string_to_unsigned_char(url_value
.u
.string
);
279 trim_chars(url
, ' ', 0);
281 struct SEE_value target_value
;
283 SEE_ToString(interp
, argv
[1], &target_value
);
284 frame
= see_string_to_unsigned_char(target_value
.u
.string
);
290 /* TODO: Support for window naming and perhaps some window features? */
292 url2
= join_urls(doc_view
->document
->uri
, url
);
298 uri
= get_uri(url2
, 0);
305 if (frame
&& *frame
&& c_strcasecmp(frame
, "_blank")) {
306 struct delayed_open
*deo
= mem_calloc(1, sizeof(*deo
));
310 deo
->uri
= get_uri_reference(uri
);
311 deo
->target
= stracpy(frame
);
312 /* target will be freed in delayed_goto_uri_frame */
313 register_bottom_half(delayed_goto_uri_frame
, deo
);
318 if (!get_cmd_opt_bool("no-connect")
319 && !get_cmd_opt_bool("no-home")
320 && !get_cmd_opt_bool("anonymous")
321 && can_open_in_new(ses
->tab
->term
)) {
322 open_uri_in_new_window(ses
, uri
, NULL
, ENV_ANY
,
323 CACHE_MODE_NORMAL
, TASK_NONE
);
325 /* When opening a new tab, we might get rerendered, losing our
326 * context and triggerring a disaster, so postpone that. */
327 struct delayed_open
*deo
= mem_calloc(1, sizeof(*deo
));
331 deo
->uri
= get_uri_reference(uri
);
332 register_bottom_half(delayed_open
, deo
);
342 js_setTimeout(struct SEE_interpreter
*interp
, struct SEE_object
*self
,
343 struct SEE_object
*thisobj
, int argc
, struct SEE_value
**argv
,
344 struct SEE_value
*res
)
346 struct ecmascript_interpreter
*ei
;
350 /* Do not check thisobj->objectclass. ELinks sets this
351 * function as a property of both the window object and the
352 * global object, so thisobj may validly refer to either. */
354 if (argc
!= 2) return;
355 ei
= ((struct global_object
*)interp
)->interpreter
;
356 code
= see_value_to_unsigned_char(interp
, argv
[0]);
357 timeout
= SEE_ToInt32(interp
, argv
[1]);
358 ecmascript_set_timeout(ei
, code
, timeout
);
362 init_js_window_object(struct ecmascript_interpreter
*interpreter
)
364 struct global_object
*g
= interpreter
->backend_data
;
365 struct SEE_interpreter
*interp
= &g
->interp
;
368 g
->win
= SEE_NEW(interp
, struct js_window_object
);
370 g
->win
->object
.objectclass
= &js_window_object_class
;
371 g
->win
->object
.Prototype
= NULL
;
372 g
->win
->vs
= interpreter
->vs
;
374 SEE_SET_OBJECT(&v
, (struct SEE_object
*)g
->win
);
375 SEE_OBJECT_PUT(interp
, interp
->Global
, s_window
, &v
, 0);
377 g
->win
->alert
= SEE_cfunction_make(interp
, js_window_alert
, s_alert
, 1);
378 g
->win
->open
= SEE_cfunction_make(interp
, js_window_open
, s_open
, 3);
379 g
->win
->setTimeout
= SEE_cfunction_make(interp
, js_setTimeout
, s_setTimeout
, 2);
381 SEE_OBJECT_GET(interp
, (struct SEE_object
*)g
->win
, s_top
, &v
);
382 SEE_OBJECT_PUT(interp
, interp
->Global
, s_top
, &v
, 0);
384 SEE_OBJECT_GET(interp
, (struct SEE_object
*)g
->win
, s_self
, &v
);
385 SEE_OBJECT_PUT(interp
, interp
->Global
, s_self
, &v
, 0);
387 SEE_OBJECT_GET(interp
, (struct SEE_object
*)g
->win
, s_alert
, &v
);
388 SEE_OBJECT_PUT(interp
, interp
->Global
, s_alert
, &v
, 0);
389 SEE_OBJECT_GET(interp
, (struct SEE_object
*)g
->win
, s_open
, &v
);
390 SEE_OBJECT_PUT(interp
, interp
->Global
, s_open
, &v
, 0);
391 SEE_OBJECT_GET(interp
, (struct SEE_object
*)g
->win
, s_setTimeout
, &v
);
392 SEE_OBJECT_PUT(interp
, interp
->Global
, s_setTimeout
, &v
, 0);
396 checktime(struct SEE_interpreter
*interp
)
398 struct global_object
*g
= (struct global_object
*)interp
;
400 if (time(NULL
) - g
->exec_start
> g
->max_exec_time
) {
401 struct terminal
*term
= g
->win
->vs
->doc_view
->session
->tab
->term
;
402 /* A killer script! Alert! */
403 ecmascript_timeout_dialog(term
, g
->max_exec_time
);
404 SEE_error_throw_string(interp
, interp
->Error
, s_timeout
);