diff --git a/Makefile.config.in b/Makefile.config.in index d66f55434..3eaf09396 100644 --- a/Makefile.config.in +++ b/Makefile.config.in @@ -142,6 +142,7 @@ CONFIG_RISCOS = @CONFIG_RISCOS@ CONFIG_RUBY = @CONFIG_RUBY@ CONFIG_SCANNER = @CONFIG_SCANNER@ CONFIG_SCRIPTING = @CONFIG_SCRIPTING@ +CONFIG_SEE = @CONFIG_SEE@ CONFIG_SHA1 = @CONFIG_SHA1@ CONFIG_SMALL = @CONFIG_SMALL@ CONFIG_SMB = @CONFIG_SMB@ diff --git a/configure.in b/configure.in index ca6d2d931..bb2684c70 100644 --- a/configure.in +++ b/configure.in @@ -496,6 +496,55 @@ if test "$CONFIG_WIN32" = yes; then EL_CONFIG_WIN32 fi +dnl =================================================================== +dnl Check for SEE (Simple Ecmascript Engine) +dnl =================================================================== +AC_ARG_WITH(see, [ --with-see enable Simple Ecmascript Engine (SEE) support], + [ if test "x$withval" != xno; then enable_see=yes; fi ]) + +# The following is probably bad, ugly and so on. Stolen from Guile's (1.4) +# SEE_FLAGS but I really don't want to require people to have Guile in order +# to compile CVS. Also, the macro seems to be really stupid regarding searching +# for Guile in $PATH etc. --pasky + +AC_MSG_CHECKING([for SEE]) + +if test "$enable_see" = "yes"; then + AC_MSG_RESULT(yes); + ## Based on the SEE_FLAGS macro. + + if test -d "$withval"; then + SEE_PATH="$withval:$PATH" + else + SEE_PATH="$PATH" + fi + + AC_PATH_PROG(SEE_CONFIG, libsee-config, no, $SEE_PATH) + + ## First, let's just see if we can find Guile at all. + if test "$SEE_CONFIG" != no; then + cf_result="yes"; + + SEE_LIBS="`$SEE_CONFIG --libs`" + SEE_CFLAGS="`$SEE_CONFIG --cppflags`" + LIBS="$SEE_LIBS $LIBS" + CPPFLAGS="$CPPFLAGS $SEE_CFLAGS" + EL_CONFIG(CONFIG_SEE, [SEE]) + AC_SUBST(SEE_CFLAGS) + AC_SUBST(CONFIG_SEE) + disable_spidermonkey=yes + else + if test -n "$withval" && test "x$withval" != xno; then + AC_MSG_ERROR([SEE not found]) + else + AC_MSG_WARN([SEE support disabled]) + fi + fi +else + AC_MSG_RESULT(no); +fi + + dnl =================================================================== dnl Check for SpiderMonkey, optional even if installed. dnl =================================================================== @@ -550,7 +599,7 @@ fi AC_SUBST(CONFIG_SPIDERMONKEY) -EL_CONFIG_DEPENDS(CONFIG_ECMASCRIPT, [CONFIG_SPIDERMONKEY], [ECMAScript (JavaScript)]) +EL_CONFIG_DEPENDS(CONFIG_ECMASCRIPT, [CONFIG_SEE CONFIG_SPIDERMONKEY], [ECMAScript (JavaScript)]) dnl =================================================================== diff --git a/src/ecmascript/Makefile b/src/ecmascript/Makefile index 441d00733..894a276e4 100644 --- a/src/ecmascript/Makefile +++ b/src/ecmascript/Makefile @@ -2,7 +2,10 @@ top_builddir=../.. include $(top_builddir)/Makefile.config INCLUDES += $(SPIDERMONKEY_CFLAGS) -SUBDIRS = spidermonkey -OBJS = ecmascript.o spidermonkey.o +SUBDIRS-$(CONFIG_SPIDERMONKEY) += spidermonkey +SUBDIRS-$(CONFIG_SEE) += see +OBJS-$(CONFIG_SPIDERMONKEY) += spidermonkey.o +OBJS-$(CONFIG_SEE) += see.o +OBJS = ecmascript.o include $(top_srcdir)/Makefile.lib diff --git a/src/ecmascript/ecmascript.c b/src/ecmascript/ecmascript.c index 7b9fadf50..718786ff6 100644 --- a/src/ecmascript/ecmascript.c +++ b/src/ecmascript/ecmascript.c @@ -12,7 +12,6 @@ #include "document/document.h" #include "document/view.h" #include "ecmascript/ecmascript.h" -#include "ecmascript/spidermonkey.h" #include "intl/gettext/libintl.h" #include "main/module.h" #include "protocol/uri.h" @@ -61,49 +60,6 @@ static struct option_info ecmascript_options[] = { NULL_OPTION_INFO, }; -#define get_ecmascript_enable() get_opt_bool("ecmascript.enable") - - -static void -ecmascript_init(struct module *module) -{ - spidermonkey_init(); -} - -static void -ecmascript_done(struct module *module) -{ - spidermonkey_done(); -} - - -struct ecmascript_interpreter * -ecmascript_get_interpreter(struct view_state *vs) -{ - struct ecmascript_interpreter *interpreter; - - assert(vs); - - interpreter = mem_calloc(1, sizeof(*interpreter)); - if (!interpreter) - return NULL; - - interpreter->vs = vs; - init_list(interpreter->onload_snippets); - spidermonkey_get_interpreter(interpreter); - - return interpreter; -} - -void -ecmascript_put_interpreter(struct ecmascript_interpreter *interpreter) -{ - assert(interpreter); - spidermonkey_put_interpreter(interpreter); - free_string_list(&interpreter->onload_snippets); - mem_free(interpreter); -} - void ecmascript_reset_state(struct view_state *vs) { @@ -124,40 +80,6 @@ ecmascript_reset_state(struct view_state *vs) vs->ecmascript_fragile = 1; } - -void -ecmascript_eval(struct ecmascript_interpreter *interpreter, - struct string *code) -{ - if (!get_ecmascript_enable()) - return; - assert(interpreter); - spidermonkey_eval(interpreter, code); -} - - -unsigned char * -ecmascript_eval_stringback(struct ecmascript_interpreter *interpreter, - struct string *code) -{ - if (!get_ecmascript_enable()) - return NULL; - assert(interpreter); - return spidermonkey_eval_stringback(interpreter, code); -} - - -int -ecmascript_eval_boolback(struct ecmascript_interpreter *interpreter, - struct string *code) -{ - if (!get_ecmascript_enable()) - return -1; - assert(interpreter); - return spidermonkey_eval_boolback(interpreter, code); -} - - void ecmascript_protocol_handler(struct session *ses, struct uri *uri) { @@ -197,6 +119,20 @@ ecmascript_protocol_handler(struct session *ses, struct uri *uri) } +void +ecmascript_timeout_dialog(struct terminal *term, int max_exec_time) +{ + info_box(term, MSGBOX_FREE_TEXT, + N_("JavaScript Emergency"), ALIGN_LEFT, + msg_text(term, + N_("A script embedded in the current document was running\n" + "for more than %d seconds. This probably means there is\n" + "a bug in the script and it could have halted the whole\n" + "ELinks, so the script execution was interrupted."), + max_exec_time)); + +} + struct module ecmascript_module = struct_module( /* name: */ N_("ECMAScript"), /* options: */ ecmascript_options, diff --git a/src/ecmascript/ecmascript.h b/src/ecmascript/ecmascript.h index fd9f13cb4..58429e039 100644 --- a/src/ecmascript/ecmascript.h +++ b/src/ecmascript/ecmascript.h @@ -9,9 +9,12 @@ #include "util/time.h" struct string; +struct terminal; struct uri; struct view_state; +#define get_ecmascript_enable() get_opt_bool("ecmascript.enable") + struct ecmascript_interpreter { struct view_state *vs; void *backend_data; @@ -63,6 +66,11 @@ int ecmascript_eval_boolback(struct ecmascript_interpreter *interpreter, struct * follows a link with this synstax. */ void ecmascript_protocol_handler(struct session *ses, struct uri *uri); +void ecmascript_init(struct module *); +void ecmascript_done(struct module *); +void ecmascript_timeout_dialog(struct terminal *term, int max_exec_time); + + extern struct module ecmascript_module; #endif diff --git a/src/ecmascript/see.c b/src/ecmascript/see.c new file mode 100644 index 000000000..b9aa9b668 --- /dev/null +++ b/src/ecmascript/see.c @@ -0,0 +1,243 @@ +/* The SEE ECMAScript backend. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "elinks.h" + +#include + +#include "bfu/dialog.h" +#include "cache/cache.h" +#include "cookies/cookies.h" +#include "dialogs/menu.h" +#include "dialogs/status.h" +#include "document/html/frames.h" +#include "document/document.h" +#include "document/forms.h" +#include "document/view.h" +#include "ecmascript/ecmascript.h" +#include "ecmascript/see.h" +#include "ecmascript/see/document.h" +#include "ecmascript/see/form.h" +#include "ecmascript/see/input.h" +#include "ecmascript/see/location.h" +#include "ecmascript/see/navigator.h" +#include "ecmascript/see/strings.h" +#include "ecmascript/see/unibar.h" +#include "ecmascript/see/window.h" +#include "intl/gettext/libintl.h" +#include "main/select.h" +#include "osdep/newwin.h" +#include "osdep/sysname.h" +#include "protocol/http/http.h" +#include "protocol/uri.h" +#include "session/history.h" +#include "session/location.h" +#include "session/session.h" +#include "session/task.h" +#include "terminal/tab.h" +#include "terminal/terminal.h" +#include "util/conv.h" +#include "util/string.h" +#include "viewer/text/draw.h" +#include "viewer/text/form.h" +#include "viewer/text/link.h" +#include "viewer/text/vs.h" + + +/*** Global methods */ + + +/* TODO? Are there any which need to be implemented? */ + + + +/*** The ELinks interface */ + +void +ecmascript_init(struct module *module) +{ + see_init(); +} + +void +ecmascript_done(struct module *module) +{ + see_done(); +} + +struct ecmascript_interpreter * +ecmascript_get_interpreter(struct view_state *vs) +{ + struct ecmascript_interpreter *interpreter; + + assert(vs); + + interpreter = mem_calloc(1, sizeof(*interpreter)); + if (!interpreter) + return NULL; + + interpreter->vs = vs; + init_list(interpreter->onload_snippets); + see_get_interpreter(interpreter); + + return interpreter; +} + +void +ecmascript_put_interpreter(struct ecmascript_interpreter *interpreter) +{ + assert(interpreter); + see_put_interpreter(interpreter); + free_string_list(&interpreter->onload_snippets); + mem_free(interpreter); +} + +void +ecmascript_eval(struct ecmascript_interpreter *interpreter, + struct string *code) +{ + if (!get_ecmascript_enable()) + return; + assert(interpreter); + see_eval(interpreter, code); +} + +unsigned char * +ecmascript_eval_stringback(struct ecmascript_interpreter *interpreter, + struct string *code) +{ + if (!get_ecmascript_enable()) + return NULL; + assert(interpreter); + return see_eval_stringback(interpreter, code); +} + +int +ecmascript_eval_boolback(struct ecmascript_interpreter *interpreter, + struct string *code) +{ + if (!get_ecmascript_enable()) + return -1; + assert(interpreter); + return see_eval_boolback(interpreter, code); +} + +void +see_init(void) +{ + init_intern_strings(); +} + +void +see_done(void) +{ +} + +void * +see_get_interpreter(struct ecmascript_interpreter *interpreter) +{ + struct global_object *g = SEE_NEW(NULL, struct global_object); + struct SEE_interpreter *interp = &g->interp; + + interpreter->backend_data = g; + g->max_exec_time = get_opt_int("ecmascript.max_exec_time"); + g->exec_start = time(NULL); + SEE_interpreter_init(interp); + init_js_window_object(interpreter); + init_js_menubar_object(interpreter); + init_js_statusbar_object(interpreter); + init_js_navigator_object(interpreter); + init_js_history_object(interpreter); + init_js_location_object(interpreter); + init_js_document_object(interpreter); + init_js_forms_object(interpreter); + return interp; +} + +void +see_put_interpreter(struct ecmascript_interpreter *interpreter) +{ + interpreter->backend_data = NULL; +} + +void +see_eval(struct ecmascript_interpreter *interpreter, + struct string *code) +{ + + struct SEE_interpreter *interp = interpreter->backend_data; + struct global_object *g = (struct global_object *)interp; + struct SEE_input *input = SEE_input_elinks(interp, code->source); + SEE_try_context_t try_ctxt; + struct SEE_value result; + struct SEE_value v; + + g->exec_start = time(NULL); + SEE_TRY(interp, try_ctxt) { + SEE_Global_eval(interp, input, &result); + } + + SEE_INPUT_CLOSE(input); + SEE_CAUGHT(try_ctxt); +} + + +unsigned char * +see_eval_stringback(struct ecmascript_interpreter *interpreter, + struct string *code) +{ + struct SEE_interpreter *interp = interpreter->backend_data; + struct global_object *g = (struct global_object *)interp; + struct SEE_input *input = SEE_input_elinks(interp, code->source); + SEE_try_context_t try_ctxt; + struct SEE_value result; + unsigned char *string = NULL; + + g->exec_start = time(NULL); + SEE_TRY(interp, try_ctxt) { + SEE_Global_eval(interp, input, &result); + if (SEE_VALUE_GET_TYPE(&result) != SEE_NULL) + string = SEE_value_to_unsigned_char(interp, &result); + + } + SEE_INPUT_CLOSE(input); + if (SEE_CAUGHT(try_ctxt)) { + return NULL; + } + return string; +} + +int +see_eval_boolback(struct ecmascript_interpreter *interpreter, + struct string *code) +{ + struct SEE_interpreter *interp = interpreter->backend_data; + struct global_object *g = (struct global_object *)interp; + struct SEE_input *input = SEE_input_elinks(interp, code->source); + SEE_try_context_t try_ctxt; + struct SEE_value result; + SEE_int32_t res = 0; + + g->exec_start = time(NULL); + SEE_TRY(interp, try_ctxt) { + SEE_Global_eval(interp, input, &result); + /* history.back() returns SEE_NULL */ + if (SEE_VALUE_GET_TYPE(&result) == SEE_NULL) + res = 0; + else + res = SEE_ToInt32(interp, &result); + } + + SEE_INPUT_CLOSE(input); + if (SEE_CAUGHT(try_ctxt)) { + return -1; + } + return res; +} diff --git a/src/ecmascript/see.h b/src/ecmascript/see.h new file mode 100644 index 000000000..206be2cb8 --- /dev/null +++ b/src/ecmascript/see.h @@ -0,0 +1,17 @@ +#ifndef EL__ECMASCRIPT_SEE_H +#define EL__ECMASCRIPT_SEE_H + +struct ecmascript_interpreter; +struct string; + +void see_init(); +void see_done(); + +void *see_get_interpreter(struct ecmascript_interpreter *interpreter); +void see_put_interpreter(struct ecmascript_interpreter *interpreter); + +void see_eval(struct ecmascript_interpreter *interpreter, struct string *code); +unsigned char *see_eval_stringback(struct ecmascript_interpreter *interpreter, struct string *code); +int see_eval_boolback(struct ecmascript_interpreter *interpreter, struct string *code); + +#endif diff --git a/src/ecmascript/see.o b/src/ecmascript/see.o new file mode 100644 index 000000000..a62cbd352 Binary files /dev/null and b/src/ecmascript/see.o differ diff --git a/src/ecmascript/see/Makefile b/src/ecmascript/see/Makefile new file mode 100644 index 000000000..f1c4b9e81 --- /dev/null +++ b/src/ecmascript/see/Makefile @@ -0,0 +1,6 @@ +top_builddir=../../.. +include $(top_builddir)/Makefile.config + +OBJS = document.o form.o input.o location.o navigator.o strings.o unibar.o window.o + +include $(top_srcdir)/Makefile.lib diff --git a/src/ecmascript/see/document.c b/src/ecmascript/see/document.c new file mode 100644 index 000000000..888edaa00 --- /dev/null +++ b/src/ecmascript/see/document.c @@ -0,0 +1,257 @@ +/* The SEE document object implementation. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "elinks.h" + +#include + +#include "bfu/dialog.h" +#include "cache/cache.h" +#include "cookies/cookies.h" +#include "dialogs/menu.h" +#include "dialogs/status.h" +#include "document/html/frames.h" +#include "document/document.h" +#include "document/forms.h" +#include "document/view.h" +#include "ecmascript/ecmascript.h" +#include "ecmascript/see/document.h" +#include "ecmascript/see/form.h" +#include "ecmascript/see/input.h" +#include "ecmascript/see/strings.h" +#include "ecmascript/see/window.h" +#include "intl/gettext/libintl.h" +#include "main/select.h" +#include "osdep/newwin.h" +#include "osdep/sysname.h" +#include "protocol/http/http.h" +#include "protocol/uri.h" +#include "session/history.h" +#include "session/location.h" +#include "session/session.h" +#include "session/task.h" +#include "terminal/tab.h" +#include "terminal/terminal.h" +#include "util/conv.h" +#include "util/memory.h" +#include "util/string.h" +#include "viewer/text/draw.h" +#include "viewer/text/form.h" +#include "viewer/text/link.h" +#include "viewer/text/vs.h" + +static void document_get(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *); +static void document_put(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *, int); +static int document_canput(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *); +static int document_hasproperty(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *); +static void js_document_write(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *); + +void location_goto(struct document_view *, unsigned char *); + +struct SEE_objectclass js_document_object_class = { + NULL, + document_get, + document_put, + document_canput, + document_hasproperty, + SEE_no_delete, + SEE_no_defaultvalue, + NULL, + NULL, + NULL, + NULL +}; + +static void +document_get(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p, struct SEE_value *res) +{ + struct global_object *g = (struct global_object *)interp; + struct js_window_object *win = g->win; + struct view_state *vs = win->vs; + struct document_view *doc_view = vs->doc_view; + struct document *document = doc_view->document; + struct js_document_object *doc = (struct js_document_object *)o; + struct session *ses = doc_view->session; + struct SEE_string *str; + unsigned char *string; + + checktime(interp); + SEE_SET_UNDEFINED(res); + + if (p == s_cookie) { +#ifdef CONFIG_COOKIES + struct string *cookies = send_cookies(vs->uri); + + if (cookies) { + static unsigned char cookiestr[1024]; + strncpy(cookiestr, cookies->source, 1024); + done_string(cookies); + + str = string_to_SEE_string(interp, cookiestr); + } else { + str = string_to_SEE_string(interp, ""); + } + SEE_SET_STRING(res, str); +#endif + } else if (p == s_title) { + str = string_to_SEE_string(interp, document->title); + SEE_SET_STRING(res, str); + } else if (p == s_url) { + string = get_uri_string(document->uri, URI_ORIGINAL); + str = string_to_SEE_string(interp, string); + mem_free_if(string); + SEE_SET_STRING(res, str); + } else if (p == s_location) { + SEE_OBJECT_GET(interp, interp->Global, s_location, res); + } else if (p == s_referrer) { + switch (get_opt_int("protocol.http.referer.policy")) { + case REFERER_NONE: + SEE_SET_UNDEFINED(res); + break; + case REFERER_FAKE: + str = string_to_SEE_string(interp, + get_opt_str("protocol.http.referer.fake")); + SEE_SET_STRING(res, str); + break; + case REFERER_TRUE: + if (ses->referrer) { + string = get_uri_string(ses->referrer, URI_HTTP_REFERRER); + str = string_to_SEE_string(interp, string); + mem_free_if(string); + SEE_SET_STRING(res, str); + } + break; + case REFERER_SAME_URL: + string = get_uri_string(document->uri, URI_HTTP_REFERRER); + str = string_to_SEE_string(interp, string); + mem_free_if(string); + SEE_SET_STRING(res, str); + break; + + } + } else if (p == s_forms) { + SEE_SET_OBJECT(res, doc->forms); + } else { + struct form *form; + unsigned char *string = SEE_string_to_unsigned_char(p); + struct form_view *form_view; + struct js_form *form_object; + + foreach (form, document->forms) { + if (!form->name || strcasecmp(string, form->name)) + continue; + mem_free_if(string); + form_view = find_form_view(doc_view, form); + form_object = js_get_form_object(interp, doc, form_view); + SEE_SET_OBJECT(res, (struct SEE_object *)form_object); + break; + } + } +} + +static void +document_put(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p, struct SEE_value *val, int attr) +{ + struct global_object *g = (struct global_object *)interp; + struct view_state *vs = g->win->vs; + struct document_view *doc_view = vs->doc_view; + struct document *document = doc_view->document; + struct js_document_object *doc = (struct js_document_object *)o; + struct SEE_value res; + unsigned char *string; + + checktime(interp); + if (p == s_forms) { + SEE_ToObject(interp, val, &res); + doc->forms = res.u.object; + } else if (p == s_title) { + string = SEE_value_to_unsigned_char(interp, val); + mem_free_set(&document->title, string); + print_screen_status(doc_view->session); + } else if (p == s_location || p == s_url) { + /* According to the specs this should be readonly but some + * broken sites still assign to it (i.e. + * http://www.e-handelsfonden.dk/validering.asp?URL=www.polyteknisk.dk). + * So emulate window.location. */ + string = SEE_value_to_unsigned_char(interp, val); + location_goto(doc_view, string); + mem_free_if(string); + } else if (p == s_cookie) { +#ifdef CONFIG_COOKIES + string = SEE_value_to_unsigned_char(interp, val); + set_cookie(vs->uri, string); + mem_free_if(string); +#endif + } + + +} + +static void +js_document_write(struct SEE_interpreter *interp, struct SEE_object *self, + struct SEE_object *thisobj, int argc, struct SEE_value **argv, + struct SEE_value *res) +{ +#ifdef CONFIG_LEDS + struct global_object *g = (struct global_object *)interp; + struct view_state *vs = g->win->vs; + + /* XXX: I don't know about you, but I have *ENOUGH* of those 'Undefined + * function' errors, I want to see just the useful ones. So just + * lighting a led and going away, no muss, no fuss. --pasky */ + /* TODO: Perhaps we can introduce ecmascript.error_report_unsupported + * -> "Show information about the document using some valid, + * nevertheless unsupported methods/properties." --pasky too */ + + set_led_value(vs->doc_view->session->status.ecmascript_led, 'J'); +#endif + checktime(interp); + SEE_SET_BOOLEAN(res, 0); +} + +static int +document_canput(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p) +{ + checktime(interp); + if (p == s_location || p == s_url || p == s_cookie) + return 1; + return 0; +} + +static int +document_hasproperty(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p) +{ + checktime(interp); + /* all unknown properties return UNDEFINED value */ + return 1; +} + + +void +init_js_document_object(struct ecmascript_interpreter *interpreter) +{ + struct global_object *g = interpreter->backend_data; + struct SEE_interpreter *interp = &g->interp; + struct SEE_value v; + struct js_document_object *doc = SEE_NEW(interp, + struct js_document_object); + + doc->object.objectclass = &js_document_object_class; + doc->object.objectclass->Class = s_document; + doc->object.Prototype = NULL; + + SEE_SET_OBJECT(&v, (struct SEE_object *)doc); + SEE_OBJECT_PUT(interp, interp->Global, s_document, &v, 0); + + doc->write = SEE_cfunction_make(interp, js_document_write, s_write, 1); +} diff --git a/src/ecmascript/see/document.h b/src/ecmascript/see/document.h new file mode 100644 index 000000000..1fde46eba --- /dev/null +++ b/src/ecmascript/see/document.h @@ -0,0 +1,14 @@ +#ifndef EL__ECMASCRIPT_SEE_DOCUMENT_H +#define EL__ECMASCRIPT_SEE_DOCUMENT_H + +struct ecmascript_interpreter; + +struct js_document_object { + struct SEE_object object; + struct SEE_object *write; + struct SEE_object *forms; +}; + +void init_js_document_object(struct ecmascript_interpreter *); + +#endif diff --git a/src/ecmascript/see/form.c b/src/ecmascript/see/form.c new file mode 100644 index 000000000..db343d9f2 --- /dev/null +++ b/src/ecmascript/see/form.c @@ -0,0 +1,964 @@ +/* The SEE form object implementation. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "elinks.h" + +#include + +#include "bfu/dialog.h" +#include "cache/cache.h" +#include "cookies/cookies.h" +#include "dialogs/menu.h" +#include "dialogs/status.h" +#include "document/html/frames.h" +#include "document/document.h" +#include "document/forms.h" +#include "document/view.h" +#include "ecmascript/ecmascript.h" +#include "ecmascript/see/document.h" +#include "ecmascript/see/form.h" +#include "ecmascript/see/input.h" +#include "ecmascript/see/strings.h" +#include "ecmascript/see/window.h" +#include "intl/gettext/libintl.h" +#include "main/select.h" +#include "osdep/newwin.h" +#include "osdep/sysname.h" +#include "protocol/http/http.h" +#include "protocol/uri.h" +#include "session/history.h" +#include "session/location.h" +#include "session/session.h" +#include "session/task.h" +#include "terminal/tab.h" +#include "terminal/terminal.h" +#include "util/conv.h" +#include "util/memory.h" +#include "util/string.h" +#include "viewer/text/draw.h" +#include "viewer/text/form.h" +#include "viewer/text/link.h" +#include "viewer/text/vs.h" + +static void input_get(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *); +static void input_put(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *, int); +static void js_input_blur(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *); +static void js_input_click(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *); +static void js_input_focus(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *); +static void js_input_select(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *); +static int input_canput(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *); +static int input_hasproperty(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *); +static struct js_input *js_get_input_object(struct SEE_interpreter *, struct js_form *, struct form_state *); +static struct js_input *js_get_form_control_object(struct SEE_interpreter *, struct js_form *, enum form_type, struct form_state *); + +static void js_form_elems_item(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *); +static void js_form_elems_namedItem(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *); +static void form_elems_get(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *); +static int form_elems_hasproperty(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *); + +static void js_forms_item(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *); +static void js_forms_namedItem(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *); +static void forms_get(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *); +static int forms_hasproperty(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *); + +static void form_get(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *); +static void form_put(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *, int); +static int form_canput(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *); +static int form_hasproperty(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *); +static void js_form_reset(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *); +static void js_form_submit(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *); + + +struct SEE_objectclass js_input_object_class = { + NULL, + input_get, + input_put, + input_canput, + input_hasproperty, + SEE_no_delete, + SEE_no_defaultvalue, + NULL, + NULL, + NULL, + NULL +}; + +struct SEE_objectclass js_form_elems_class = { + NULL, + form_elems_get, + SEE_no_put, + SEE_no_canput, + form_elems_hasproperty, + SEE_no_delete, + SEE_no_defaultvalue, + NULL, + NULL, + NULL, + NULL +}; + +struct SEE_objectclass js_forms_object_class = { + NULL, + forms_get, + SEE_no_put, + SEE_no_canput, + forms_hasproperty, + SEE_no_delete, + SEE_no_defaultvalue, + NULL, + NULL, + NULL, + NULL +}; + +struct SEE_objectclass js_form_class = { + NULL, + form_get, + form_put, + form_canput, + form_hasproperty, + SEE_no_delete, + SEE_no_defaultvalue, + NULL, + NULL, + NULL, + NULL +}; + +struct js_input { + struct SEE_object object; + struct js_form *parent; + struct form_state *fs; + struct SEE_object *blur; + struct SEE_object *click; + struct SEE_object *focus; + struct SEE_object *select; +}; + +struct js_forms_object { + struct SEE_object object; + struct js_document_object *parent; + struct SEE_object *item; + struct SEE_object *namedItem; +}; + +struct js_form_elems { + struct SEE_object object; + struct js_form *parent; + struct SEE_object *item; + struct SEE_object *namedItem; +}; + + +static void +input_get(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p, struct SEE_value *res) +{ + struct global_object *g = (struct global_object *)interp; + struct view_state *vs = g->win->vs; + struct document_view *doc_view = vs->doc_view; + struct document *document = doc_view->document; + struct js_input *input = (struct js_input *)o; + struct js_form *parent = input->parent; + struct form_state *fs = input->fs; + struct form_control *fc = find_form_control(document, fs); + int linknum; + struct link *link = NULL; + struct SEE_string *str; + + assert(fc); + assert(fc->form && fs); + + checktime(interp); + linknum = get_form_control_link(document, fc); + /* Hiddens have no link. */ + if (linknum >= 0) link = &document->links[linknum]; + SEE_SET_UNDEFINED(res); + + if (p == s_accessKey) { + struct string keystr; + if (!link) + return; + + init_string(&keystr); + add_accesskey_to_string(&keystr, link->accesskey); + str = string_to_SEE_string(interp, keystr.source); + SEE_SET_STRING(res, str); + done_string(&keystr); + } else if (p == s_alt) { + str = string_to_SEE_string(interp, fc->alt); + SEE_SET_STRING(res, str); + } else if (p == s_checked) { + SEE_SET_BOOLEAN(res, fs->state); + } else if (p == s_defaultChecked) { + SEE_SET_BOOLEAN(res, fc->default_state); + } else if (p == s_defaultValue) { + str = string_to_SEE_string(interp, fc->default_value); + SEE_SET_STRING(res, str); + } else if (p == s_disabled) { + /* FIXME: --pasky */ + SEE_SET_BOOLEAN(res, fc->mode == FORM_MODE_DISABLED); + } else if (p == s_form) { + SEE_SET_OBJECT(res, (struct SEE_object *)parent); + } else if (p == s_maxLength) { + SEE_SET_NUMBER(res, fc->maxlength); + } else if (p == s_name) { + str = string_to_SEE_string(interp, fc->name); + SEE_SET_STRING(res, str); + } else if (p == s_readonly) { + /* FIXME: --pasky */ + SEE_SET_BOOLEAN(res, fc->mode == FORM_MODE_READONLY); + } else if (p == s_size) { + SEE_SET_NUMBER(res, fc->size); + } else if (p == s_src) { + if (link && link->where_img) { + str = string_to_SEE_string(interp, link->where_img); + SEE_SET_STRING(res, str); + } + } else if (p == s_tabindex) { + if (link) { + /* FIXME: This is WRONG. --pasky */ + SEE_SET_NUMBER(res, link->number); + } + } else if (p == s_type) { + switch (fc->type) { + case FC_TEXT: str = s_text; break; + case FC_PASSWORD: str = s_password; break; + case FC_FILE: str = s_file; break; + case FC_CHECKBOX: str = s_checkbox; break; + case FC_RADIO: str = s_radio; break; + case FC_SUBMIT: str = s_submit; break; + case FC_IMAGE: str = s_image; break; + case FC_RESET: str = s_reset; break; + case FC_BUTTON: str = s_button; break; + case FC_HIDDEN: str = s_hidden; break; + default: str = NULL; + } + if (str) { + SEE_SET_STRING(res, str); + } + } else if (p == s_value) { + str = string_to_SEE_string(interp, fs->value); + SEE_SET_STRING(res, str); + } +} + +static void +input_put(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p, struct SEE_value *val, int attr) +{ + struct global_object *g = (struct global_object *)interp; + struct view_state *vs = g->win->vs; + struct document_view *doc_view = vs->doc_view; + struct document *document = doc_view->document; + struct js_input *input = (struct js_input *)o; + struct form_state *fs = input->fs; + struct form_control *fc = find_form_control(document, fs); + int linknum; + struct link *link = NULL; + unsigned char *string = NULL; + + assert(fc); + assert(fc->form && fs); + + checktime(interp); + linknum = get_form_control_link(document, fc); + /* Hiddens have no link. */ + if (linknum >= 0) link = &document->links[linknum]; + + if (p == s_accessKey) { + if (link) { + string = SEE_value_to_unsigned_char(interp, val); + if (!string) + return; + link->accesskey = accesskey_string_to_unicode(string); + mem_free(string); + } + } else if (p == s_alt) { + string = SEE_value_to_unsigned_char(interp, val); + mem_free_set(&fc->alt, string); + } else if (p == s_checked) { + if (fc->type != FC_CHECKBOX && fc->type != FC_RADIO) + return; + fs->state = SEE_ToUint32(interp, val); + } else if (p == s_disabled) { + /* FIXME: --pasky */ + SEE_uint32_t boo = SEE_ToUint32(interp, val); + fc->mode = (boo ? FORM_MODE_DISABLED + : (fc->mode == FORM_MODE_READONLY ? FORM_MODE_READONLY + : FORM_MODE_NORMAL)); + } else if (p == s_maxLength) { + string = SEE_value_to_unsigned_char(interp, val); + if (!string) + return; + fc->maxlength = atol(string); + mem_free(string); + } else if (p == s_name) { + string = SEE_value_to_unsigned_char(interp, val); + mem_free_set(&fc->name, string); + } else if (p == s_readonly) { + SEE_uint32_t boo = SEE_ToUint32(interp, val); + fc->mode = (boo ? FORM_MODE_READONLY + : fc->mode == FORM_MODE_DISABLED ? FORM_MODE_DISABLED + : FORM_MODE_NORMAL); + } else if (p == s_src) { + if (link) { + string = SEE_value_to_unsigned_char(interp, val); + mem_free_set(&link->where_img, string); + } + } else if (p == s_value) { + if (fc->type == FC_FILE) + return; + string = SEE_value_to_unsigned_char(interp, val); + mem_free_set(&fs->value, string); + if (fc->type == FC_TEXT || fc->type == FC_PASSWORD) + fs->state = strlen(fs->value); + } +} + +static void +js_input_blur(struct SEE_interpreter *interp, struct SEE_object *self, + struct SEE_object *thisobj, int argc, struct SEE_value **argv, + struct SEE_value *res) +{ + /* We are a text-mode browser and there *always* has to be something + * selected. So we do nothing for now. (That was easy.) */ +} + +static void +js_input_click(struct SEE_interpreter *interp, struct SEE_object *self, + struct SEE_object *thisobj, int argc, struct SEE_value **argv, + struct SEE_value *res) +{ + struct global_object *g = (struct global_object *)interp; + struct view_state *vs = g->win->vs; + struct document_view *doc_view = vs->doc_view; + struct document *document = doc_view->document; + struct session *ses = doc_view->session; + struct js_input *input = (struct js_input *)thisobj; + struct form_state *fs = input->fs; + struct form_control *fc; + int linknum; + + checktime(interp); + SEE_SET_BOOLEAN(res, 0); + assert(fs); + fc = find_form_control(document, fs); + assert(fc); + + linknum = get_form_control_link(document, fc); + /* Hiddens have no link. */ + if (linknum < 0) + return; + + /* Restore old current_link afterwards? */ + jump_to_link_number(ses, doc_view, linknum); + if (enter(ses, doc_view, 0) == FRAME_EVENT_REFRESH) + refresh_view(ses, doc_view, 0); + else + print_screen_status(ses); +} + +static void +js_input_focus(struct SEE_interpreter *interp, struct SEE_object *self, + struct SEE_object *thisobj, int argc, struct SEE_value **argv, + struct SEE_value *res) +{ + struct global_object *g = (struct global_object *)interp; + struct view_state *vs = g->win->vs; + struct document_view *doc_view = vs->doc_view; + struct document *document = doc_view->document; + struct session *ses = doc_view->session; + struct js_input *input = (struct js_input *)thisobj; + struct form_state *fs = input->fs; + struct form_control *fc; + int linknum; + + checktime(interp); + assert(fs); + fc = find_form_control(document, fs); + assert(fc); + + linknum = get_form_control_link(document, fc); + /* Hiddens have no link. */ + if (linknum < 0) + return; + + jump_to_link_number(ses, doc_view, linknum); + +} + +static void +js_input_select(struct SEE_interpreter *interp, struct SEE_object *self, + struct SEE_object *thisobj, int argc, struct SEE_value **argv, + struct SEE_value *res) +{ + checktime(interp); + /* We support no text selecting yet. So we do nothing for now. + * (That was easy, too.) */ +} + +static int +input_canput(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p) +{ + checktime(interp); + return 1; +} + +static int +input_hasproperty(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p) +{ + /* all unknown properties return UNDEFINED value */ + checktime(interp); + return 1; +} + +static struct js_input * +js_get_input_object(struct SEE_interpreter *interp, struct js_form *jsform, + struct form_state *fs) +{ + struct js_input *jsinput; + + checktime(interp); + if (fs->ecmascript_obj) + return fs->ecmascript_obj; + + /* jsform ('form') is input's parent */ + /* FIXME: That is NOT correct since the real containing element + * should be its parent, but gimme DOM first. --pasky */ + jsinput = SEE_NEW(interp, struct js_input); + + jsinput->object.objectclass = &js_input_object_class; + jsinput->object.objectclass->Class = s_input; + jsinput->object.Prototype = NULL; + + jsinput->blur = SEE_cfunction_make(interp, js_input_blur, s_blur, 0); + jsinput->click = SEE_cfunction_make(interp, js_input_click, s_click, 0); + jsinput->focus = SEE_cfunction_make(interp, js_input_focus, s_focus, 0); + jsinput->select = SEE_cfunction_make(interp, js_input_select, s_select, 0); + + jsinput->fs = fs; + jsinput->parent = jsform; + + fs->ecmascript_obj = jsinput; + return jsinput; +} + +static struct js_input * +js_get_form_control_object(struct SEE_interpreter *interp, struct js_form *jsform, + enum form_type type, struct form_state *fs) +{ + checktime(interp); + switch (type) { + case FC_TEXT: + case FC_PASSWORD: + case FC_FILE: + case FC_CHECKBOX: + case FC_RADIO: + case FC_SUBMIT: + case FC_IMAGE: + case FC_RESET: + case FC_BUTTON: + case FC_HIDDEN: + return js_get_input_object(interp, jsform, fs); + + case FC_TEXTAREA: + case FC_SELECT: + /* TODO */ + return NULL; + + default: + INTERNAL("Weird fc->type %d", type); + return NULL; + } +} + + + + +static void +js_form_elems_item(struct SEE_interpreter *interp, struct SEE_object *self, + struct SEE_object *thisobj, int argc, struct SEE_value **argv, + struct SEE_value *res) +{ + struct global_object *g = (struct global_object *)interp; + struct view_state *vs = g->win->vs; + struct document_view *doc_view = vs->doc_view; + struct document *document = doc_view->document; + struct js_form_elems *jsfe = (struct js_form_elems *)thisobj; + struct js_form *parent_form = jsfe->parent; + struct form_view *fv = parent_form->fv; + struct form *form = find_form_by_form_view(document, fv); + struct form_control *fc; + unsigned char *string; + int counter = -1; + int index; + + checktime(interp); + SEE_SET_UNDEFINED(res); + if (argc < 1) + return; + string = SEE_value_to_unsigned_char(interp, argv[0]); + if (!string) + return; + index = atol(string); + mem_free(string); + + foreach (fc, form->items) { + counter++; + if (counter == index) { + struct js_input *fcobj = js_get_form_control_object(interp, parent_form, fc->type, find_form_state(doc_view, fc)); + + if (fcobj) { + SEE_SET_OBJECT(res, (struct SEE_object *)fcobj); + } + break; + } + } + +} + +static void +js_form_elems_namedItem(struct SEE_interpreter *interp, struct SEE_object *self, + struct SEE_object *thisobj, int argc, struct SEE_value **argv, + struct SEE_value *res) +{ + struct global_object *g = (struct global_object *)interp; + struct view_state *vs = g->win->vs; + struct document_view *doc_view = vs->doc_view; + struct document *document = doc_view->document; + struct js_form_elems *jsfe = (struct js_form_elems *)thisobj; + struct js_form *parent_form = jsfe->parent; + struct form_view *fv = parent_form->fv; + struct form *form = find_form_by_form_view(document, fv); + struct form_control *fc; + unsigned char *string; + + checktime(interp); + SEE_SET_UNDEFINED(res); + if (argc < 1) + return; + string = SEE_value_to_unsigned_char(interp, argv[0]); + if (!string) + return; + + foreach (fc, form->items) { + if (fc->name && !strcasecmp(string, fc->name)) { + struct js_input *fcobj = js_get_form_control_object(interp, parent_form, fc->type, find_form_state(doc_view, fc)); + + if (fcobj) { + SEE_SET_OBJECT(res, (struct SEE_object *)fcobj); + } + break; + } + } + mem_free(string); +} + +static void +form_elems_get(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p, struct SEE_value *res) +{ + struct global_object *g = (struct global_object *)interp; + struct view_state *vs = g->win->vs; + struct document_view *doc_view = vs->doc_view; + struct document *document = doc_view->document; + struct js_form_elems *jsfe = (struct js_form_elems *)o; + struct js_form *parent_form = jsfe->parent; + struct form_view *fv = parent_form->fv; + struct form *form = find_form_by_form_view(document, fv); + + checktime(interp); + if (p == s_length) { + SEE_number_t length = list_size(&form->items); + SEE_SET_NUMBER(res, length); + } else { + unsigned char *string = SEE_string_to_unsigned_char(p); + struct SEE_value argv; + + if (!string) { + SEE_SET_UNDEFINED(res); + return; + } + SEE_SET_STRING(&argv, p); + if (string[0] >= '0' && string[1] <= '9') { + js_form_elems_item(interp, o, NULL, 1, + (struct SEE_value **)&argv, res); + } else { + js_form_elems_namedItem(interp, o, NULL, 1, + (struct SEE_value **)&argv, res); + } + mem_free(string); + } +} + +static int +form_elems_hasproperty(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p) +{ + checktime(interp); + /* all unknown properties return UNDEFINED value */ + return 1; +} + + +static void +js_forms_item(struct SEE_interpreter *interp, struct SEE_object *self, + struct SEE_object *thisobj, int argc, struct SEE_value **argv, + struct SEE_value *res) +{ + struct global_object *g = (struct global_object *)interp; + struct view_state *vs = g->win->vs; + struct js_forms_object *fo = (struct js_forms_object *)thisobj; + struct js_document_object *doc = fo->parent; + struct form_view *fv; + unsigned char *string; + int counter = -1; + int index; + + checktime(interp); + SEE_SET_UNDEFINED(res); + if (argc < 1) + return; + + string = SEE_value_to_unsigned_char(interp, argv[0]); + if (!string) + return; + index = atol(string); + mem_free(string); + + foreach (fv, vs->forms) { + counter++; + if (counter == index) { + struct js_form *obj = js_get_form_object(interp, doc, fv); + + SEE_SET_OBJECT(res, (struct SEE_object *)obj); + break; + } + } +} + +static void +js_forms_namedItem(struct SEE_interpreter *interp, struct SEE_object *self, + struct SEE_object *thisobj, int argc, struct SEE_value **argv, + struct SEE_value *res) +{ + struct global_object *g = (struct global_object *)interp; + struct view_state *vs = g->win->vs; + struct document_view *doc_view = vs->doc_view; + struct document *document = doc_view->document; + struct js_forms_object *fo = (struct js_forms_object *)thisobj; + struct js_document_object *doc = fo->parent; + struct form *form; + unsigned char *string; + + checktime(interp); + SEE_SET_UNDEFINED(res); + if (argc < 1) + return; + + string = SEE_value_to_unsigned_char(interp, argv[0]); + if (!string) + return; + foreach (form, document->forms) { + if (form->name && !strcasecmp(string, form->name)) { + struct form_view *fv = find_form_view(doc_view, form); + struct js_form *obj = js_get_form_object(interp, + doc, fv); + + SEE_SET_OBJECT(res, (struct SEE_object *)obj); + break; + + } + } + mem_free(string); +} + +static void +forms_get(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p, struct SEE_value *res) +{ + struct global_object *g = (struct global_object *)interp; + struct view_state *vs = g->win->vs; + struct document_view *doc_view = vs->doc_view; + struct document *document = doc_view->document; + + checktime(interp); + if (p == s_length) { + SEE_number_t length = list_size(&document->forms); + SEE_SET_NUMBER(res, length); + } else { + unsigned char *string = SEE_string_to_unsigned_char(p); + struct SEE_value argv; + + if (!string) { + SEE_SET_UNDEFINED(res); + return; + } + SEE_SET_STRING(&argv, p); + if (string[0] >= '0' && string[1] <= '9') { + js_forms_item(interp, o, NULL, 1, + (struct SEE_value **)&argv, res); + } else { + js_forms_namedItem(interp, o, NULL, 1, + (struct SEE_value **)&argv, res); + } + mem_free(string); + } +} + +static int +forms_hasproperty(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p) +{ + checktime(interp); + /* all unknown properties return UNDEFINED value */ + return 1; +} + + + +static void +form_get(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p, struct SEE_value *res) +{ + struct global_object *g = (struct global_object *)interp; + struct view_state *vs = g->win->vs; + struct document_view *doc_view = vs->doc_view; + struct js_form *js_form = (struct js_form *)o; + struct form_view *fv = js_form->fv; + struct form *form = find_form_by_form_view(doc_view->document, fv); + struct SEE_string *str; + + checktime(interp); + SEE_SET_UNDEFINED(res); + + if (p == s_action) { + str = string_to_SEE_string(interp, form->action); + SEE_SET_STRING(res, str); + } else if (p == s_encoding) { + switch (form->method) { + case FORM_METHOD_GET: + case FORM_METHOD_POST: + /* "application/x-www-form-urlencoded" */ + SEE_SET_STRING(res, s_application_); + break; + case FORM_METHOD_POST_MP: + /* "multipart/form-data" */ + SEE_SET_STRING(res, s_multipart_); + break; + case FORM_METHOD_POST_TEXT_PLAIN: + /* "text/plain") */ + SEE_SET_STRING(res, s_textplain); + break; + } + } else if (p == s_length) { + SEE_number_t num = list_size(&form->items); + SEE_SET_NUMBER(res, num); + } else if (p == s_method) { + switch (form->method) { + case FORM_METHOD_GET: + SEE_SET_STRING(res, s_GET); + break; + + case FORM_METHOD_POST: + case FORM_METHOD_POST_MP: + case FORM_METHOD_POST_TEXT_PLAIN: + SEE_SET_STRING(res, s_POST); + break; + } + } else if (p == s_name) { + str = string_to_SEE_string(interp, form->name); + SEE_SET_STRING(res, str); + } else if (p == s_target) { + str = string_to_SEE_string(interp, form->target); + SEE_SET_STRING(res, str); + } else if (p == s_elements) { + struct js_form_elems *jsfe = SEE_NEW(interp, struct js_form_elems); + + jsfe->object.objectclass = &js_form_elems_class; + jsfe->object.objectclass->Class = s_elements; + jsfe->object.Prototype = NULL; + jsfe->parent = js_form; + jsfe->item = SEE_cfunction_make(interp, js_form_elems_item, s_item, 1); + jsfe->namedItem = SEE_cfunction_make(interp, js_form_elems_namedItem, s_namedItem, 1); + SEE_SET_OBJECT(res, (struct SEE_object *)jsfe); + } else if (p == s_submit) { + SEE_SET_OBJECT(res, js_form->submit); + } else if (p == s_reset) { + SEE_SET_OBJECT(res, js_form->reset); + } else { + unsigned char *string = SEE_string_to_unsigned_char(p); + struct form_control *fc; + + if (!string) + return; + foreach(fc, form->items) { + struct js_input *fcobj = NULL; + + if (!fc->name || strcasecmp(string, fc->name)) + continue; + fcobj = js_get_form_control_object(interp, js_form, fc->type, find_form_state(doc_view, fc)); + + if (fcobj) { + SEE_SET_OBJECT(res, (struct SEE_object *)fcobj); + } + break; + } + mem_free(string); + } +} + +static void +form_put(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p, struct SEE_value *val, int attr) +{ + struct global_object *g = (struct global_object *)interp; + struct view_state *vs = g->win->vs; + struct document_view *doc_view = vs->doc_view; + struct js_form *js_form = (struct js_form *)o; + struct form_view *fv = js_form->fv; + struct form *form = find_form_by_form_view(doc_view->document, fv); + unsigned char *string = SEE_value_to_unsigned_char(interp, val); + + checktime(interp); + if (!string) + return; + + if (p == s_action) { + mem_free_set(&form->action, string); + } else if (p == s_encoding) { + if (!strcasecmp(string, "application/x-www-form-urlencoded")) { + form->method = form->method == FORM_METHOD_GET ? FORM_METHOD_GET + : FORM_METHOD_POST; + } else if (!strcasecmp(string, "multipart/form-data")) { + form->method = FORM_METHOD_POST_MP; + } else if (!strcasecmp(string, "text/plain")) { + form->method = FORM_METHOD_POST_TEXT_PLAIN; + } + mem_free(string); + } else if (p == s_method) { + if (!strcasecmp(string, "GET")) { + form->method = FORM_METHOD_GET; + } else if (!strcasecmp(string, "POST")) { + form->method = FORM_METHOD_POST; + } + mem_free(string); + } else if (p == s_name) { + mem_free_set(&form->name, string); + } else if (p == s_target) { + mem_free_set(&form->target, string); + } +} + +static int +form_canput(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p) +{ + checktime(interp); + return 1; +} + +static int +form_hasproperty(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p) +{ + checktime(interp); + return 1; +} + +static void +js_form_reset(struct SEE_interpreter *interp, struct SEE_object *self, + struct SEE_object *thisobj, int argc, struct SEE_value **argv, + struct SEE_value *res) +{ + struct global_object *g = (struct global_object *)interp; + struct view_state *vs = g->win->vs; + struct document_view *doc_view = vs->doc_view; + struct js_form *js_form = (struct js_form *)thisobj; + struct form_view *fv = js_form->fv; + struct form *form = find_form_by_form_view(doc_view->document, fv); + + assert(form); + + checktime(interp); + do_reset_form(doc_view, form); + draw_forms(doc_view->session->tab->term, doc_view); + SEE_SET_BOOLEAN(res, 0); +} + +static void +js_form_submit(struct SEE_interpreter *interp, struct SEE_object *self, + struct SEE_object *thisobj, int argc, struct SEE_value **argv, + struct SEE_value *res) +{ + struct global_object *g = (struct global_object *)interp; + struct view_state *vs = g->win->vs; + struct document_view *doc_view = vs->doc_view; + struct session *ses = doc_view->session; + struct js_form *js_form = (struct js_form *)thisobj; + struct form_view *fv = js_form->fv; + struct form *form = find_form_by_form_view(doc_view->document, fv); + + assert(form); + checktime(interp); + submit_given_form(ses, doc_view, form); + SEE_SET_BOOLEAN(res, 0); +} + +struct js_form *js_get_form_object(struct SEE_interpreter *interp, + struct js_document_object *doc, struct form_view *fv) +{ + struct js_form *js_form; + + checktime(interp); + if (fv->ecmascript_obj) + return fv->ecmascript_obj; + + /* jsdoc ('document') is fv's parent */ + /* FIXME: That is NOT correct since the real containing element + * should be its parent, but gimme DOM first. --pasky */ + js_form = SEE_NEW(interp, struct js_form); + js_form->object.objectclass = &js_form_class; + js_form->object.objectclass->Class = s_form; + js_form->object.Prototype = NULL; /* TODO: use prototype for form */ + js_form->parent = doc; + js_form->reset = SEE_cfunction_make(interp, js_form_reset, s_reset, 0); + js_form->submit = SEE_cfunction_make(interp, js_form_submit, s_submit, 0); + js_form->fv = fv; + + fv->ecmascript_obj = js_form; + return js_form; +} + +void +init_js_forms_object(struct ecmascript_interpreter *interpreter) +{ + struct global_object *g = interpreter->backend_data; + struct SEE_interpreter *interp = &g->interp; + struct SEE_value v, document; + struct js_forms_object *forms = SEE_NEW(interp, + struct js_forms_object); + + forms->object.objectclass = &js_forms_object_class; + forms->object.objectclass->Class = s_forms; + forms->object.Prototype = NULL; + + SEE_OBJECT_GET(interp, interp->Global, s_document, &document); + SEE_SET_OBJECT(&v, (struct SEE_object *)forms); + SEE_OBJECT_PUT(interp, document.u.object, s_forms, &v, 0); + + forms->item = SEE_cfunction_make(interp, js_forms_item, s_item, 1); + forms->namedItem = SEE_cfunction_make(interp, js_forms_namedItem, + s_namedItem, 1); + forms->parent = (struct js_document_object *)document.u.object; +} diff --git a/src/ecmascript/see/form.h b/src/ecmascript/see/form.h new file mode 100644 index 000000000..707f0d3b3 --- /dev/null +++ b/src/ecmascript/see/form.h @@ -0,0 +1,19 @@ +#ifndef EL__ECMASCRIPT_SEE_FORM_H +#define EL__ECMASCRIPT_SEE_FORM_H + +struct js_document_object; +struct ecmascript_interpreter; +struct form_view; + +struct js_form { + struct SEE_object object; + struct js_document_object *parent; + struct form_view *fv; + struct SEE_object *reset; + struct SEE_object *submit; +}; + +struct js_form *js_get_form_object(struct SEE_interpreter *, struct js_document_object*, struct form_view *); +void init_js_forms_object(struct ecmascript_interpreter *); + +#endif diff --git a/src/ecmascript/see/input.c b/src/ecmascript/see/input.c new file mode 100644 index 000000000..ac9be61bc --- /dev/null +++ b/src/ecmascript/see/input.c @@ -0,0 +1,100 @@ +/* Input for SEE */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "ecmascript/see/input.h" +#include "util/memory.h" + +static SEE_unicode_t input_elinks_next(struct SEE_input *); +static void input_elinks_close(struct SEE_input *); + +static struct SEE_inputclass input_elinks_class = { + input_elinks_next, + input_elinks_close +}; + +struct input_elinks { + struct SEE_input inp; + unsigned char *s; +}; + +static SEE_unicode_t +input_elinks_next(struct SEE_input *inp) +{ + struct input_elinks *input = (struct input_elinks*)inp; + SEE_unicode_t next; + + next = input->inp.lookahead; + + if (*input->s == '\0') { + input->inp.eof = 1; + } else { + input->inp.lookahead = *input->s++; + input->inp.eof = 0; + } + return next; +} + +static void +input_elinks_close(struct SEE_input *inp) +{ + /* nothing */ +} + +struct SEE_input * +SEE_input_elinks(struct SEE_interpreter *interp, unsigned char *s) +{ + struct input_elinks *input; + + input = SEE_NEW(interp, struct input_elinks); + input->inp.interpreter = interp; + input->inp.inputclass = &input_elinks_class; + input->inp.filename = NULL; + input->inp.first_lineno = 1; + input->s = s; + SEE_INPUT_NEXT((struct SEE_input *)input); /* prime */ + return (struct SEE_input *)input; +} + +unsigned char * +SEE_string_to_unsigned_char(struct SEE_string *S) +{ + int i; + unsigned char *str = mem_alloc(S->length + 1); + + if (!str) + return NULL; + + for (i = 0; i < S->length; i++) + str[i] = (unsigned char)S->data[i]; + str[S->length] = '\0'; + return str; +} + +unsigned char * +SEE_value_to_unsigned_char(struct SEE_interpreter *interp, struct SEE_value *val) +{ + struct SEE_value result; + + SEE_ToString(interp, val, &result); + return SEE_string_to_unsigned_char(result.u.string); +} + +struct SEE_string * +string_to_SEE_string(struct SEE_interpreter *interp, unsigned char *s) +{ + unsigned int len; + unsigned int i; + struct SEE_string *str; + + len = s ? strlen(s) : 0; + str = SEE_string_new(interp, len); + str->length = len; + for (i = 0; i < len; i++) + str->data[i] = s[i]; + return str; +} diff --git a/src/ecmascript/see/input.h b/src/ecmascript/see/input.h new file mode 100644 index 000000000..d2d4755b4 --- /dev/null +++ b/src/ecmascript/see/input.h @@ -0,0 +1,11 @@ +#ifndef EL__ECMASCRIPT_SEE_INPUT_H +#define EL__ECMASCRIPT_SEE_INPUT_H + +#include + +struct SEE_input *SEE_input_elinks(struct SEE_interpreter *, unsigned char *); +unsigned char *SEE_string_to_unsigned_char(struct SEE_string *); +unsigned char *SEE_value_to_unsigned_char(struct SEE_interpreter *, struct SEE_value *); +struct SEE_string *string_to_SEE_string(struct SEE_interpreter *, unsigned char *); + +#endif diff --git a/src/ecmascript/see/location.c b/src/ecmascript/see/location.c new file mode 100644 index 000000000..38beb9097 --- /dev/null +++ b/src/ecmascript/see/location.c @@ -0,0 +1,363 @@ +/* The SEE location and history objects implementation. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "elinks.h" + +#include + +#include "bfu/dialog.h" +#include "cache/cache.h" +#include "cookies/cookies.h" +#include "dialogs/menu.h" +#include "dialogs/status.h" +#include "document/html/frames.h" +#include "document/document.h" +#include "document/forms.h" +#include "document/view.h" +#include "ecmascript/ecmascript.h" +#include "ecmascript/see/input.h" +#include "ecmascript/see/location.h" +#include "ecmascript/see/strings.h" +#include "ecmascript/see/window.h" +#include "intl/gettext/libintl.h" +#include "main/select.h" +#include "osdep/newwin.h" +#include "osdep/sysname.h" +#include "protocol/http/http.h" +#include "protocol/uri.h" +#include "session/history.h" +#include "session/location.h" +#include "session/session.h" +#include "session/task.h" +#include "terminal/tab.h" +#include "terminal/terminal.h" +#include "util/conv.h" +#include "util/memory.h" +#include "util/string.h" +#include "viewer/text/draw.h" +#include "viewer/text/form.h" +#include "viewer/text/link.h" +#include "viewer/text/vs.h" + +static void delayed_goto(void *); +static void history_get(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *); +static int history_hasproperty(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *); +static void js_history_back(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *); +static void js_history_forward(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *); +static void js_history_go(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *); +static void js_location_toString(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *); +static void location_get(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *); +static void location_put(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *, int); +static int location_hasproperty(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *); +static int location_canput(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *); + +void location_goto(struct document_view *, unsigned char *); + +struct js_history_object { + struct SEE_object object; + struct SEE_object *back; + struct SEE_object *forward; + struct SEE_object *go; +}; + +struct js_location_object { + struct SEE_object object; + struct SEE_object *toString; +}; + +struct delayed_goto { + /* It might look more convenient to pass doc_view around but it could + * disappear during wild dances inside of frames or so. */ + struct view_state *vs; + struct uri *uri; +}; + +struct SEE_objectclass js_history_object_class = { + NULL, + history_get, + SEE_no_put, + SEE_no_canput, + history_hasproperty, + SEE_no_delete, + SEE_no_defaultvalue, + NULL, + NULL, + NULL, + NULL +}; + +struct SEE_objectclass js_location_object_class = { + NULL, + location_get, + location_put, + location_canput, + location_hasproperty, + SEE_no_delete, + SEE_no_defaultvalue, + NULL, + NULL, + NULL, + NULL +}; + +static void +delayed_goto(void *data) +{ + struct delayed_goto *deg = data; + + assert(deg); + if (deg->vs->doc_view + && deg->vs->doc_view == deg->vs->doc_view->session->doc_view) { + goto_uri_frame(deg->vs->doc_view->session, deg->uri, + deg->vs->doc_view->name, + CACHE_MODE_NORMAL); + } + done_uri(deg->uri); + mem_free(deg); +} + +void +location_goto(struct document_view *doc_view, unsigned char *url) +{ + unsigned char *new_abs_url; + struct uri *new_uri; + struct delayed_goto *deg; + + /* Workaround for bug 611. Does not crash, but may lead to infinite loop.*/ + if (!doc_view) return; + new_abs_url = join_urls(doc_view->document->uri, + trim_chars(url, ' ', 0)); + if (!new_abs_url) + return; + new_uri = get_uri(new_abs_url, 0); + mem_free(new_abs_url); + if (!new_uri) + return; + deg = mem_calloc(1, sizeof(*deg)); + if (!deg) { + done_uri(new_uri); + return; + } + assert(doc_view->vs); + deg->vs = doc_view->vs; + deg->uri = new_uri; + /* It does not seem to be very safe inside of frames to + * call goto_uri() right away. */ + register_bottom_half(delayed_goto, deg); +} + + +static void +history_get(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p, struct SEE_value *res) +{ + struct js_history_object *history = (struct js_history_object *)o; + + checktime(interp); + if (p == s_back) { + SEE_SET_OBJECT(res, history->back); + } else if (p == s_forward) { + SEE_SET_OBJECT(res, history->forward); + } else if (p == s_go) { + SEE_SET_OBJECT(res, history->go); + } else { + SEE_SET_UNDEFINED(res); + } +} + +static int +history_hasproperty(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p) +{ + checktime(interp); + if (p == s_back || p == s_forward || p == s_go) + return 1; + return 0; +} + +static void +js_history_back(struct SEE_interpreter *interp, struct SEE_object *self, + struct SEE_object *thisobj, int argc, struct SEE_value **argv, + struct SEE_value *res) +{ + struct global_object *g = (struct global_object *)interp; + struct view_state *vs = g->win->vs; + struct document_view *doc_view = vs->doc_view; + struct session *ses = doc_view->session; + + SEE_SET_NULL(res); + go_back(ses); +} + +static void +js_history_forward(struct SEE_interpreter *interp, struct SEE_object *self, + struct SEE_object *thisobj, int argc, struct SEE_value **argv, + struct SEE_value *res) +{ + struct global_object *g = (struct global_object *)interp; + struct view_state *vs = g->win->vs; + struct document_view *doc_view = vs->doc_view; + struct session *ses = doc_view->session; + + checktime(interp); + SEE_SET_NULL(res); + go_unback(ses); +} + +static void +js_history_go(struct SEE_interpreter *interp, struct SEE_object *self, + struct SEE_object *thisobj, int argc, struct SEE_value **argv, + struct SEE_value *res) +{ + struct global_object *g = (struct global_object *)interp; + struct view_state *vs = g->win->vs; + struct document_view *doc_view = vs->doc_view; + struct session *ses = doc_view->session; + unsigned char *str; + int index; + struct location *loc; + + checktime(interp); + SEE_SET_NULL(res); + if (argc < 1) + return; + + str = SEE_value_to_unsigned_char(interp, argv[0]); + if (!str) + return; + + index = atol(str); + mem_free(str); + + for (loc = cur_loc(ses); + loc != (struct location *) &ses->history.history; + loc = index > 0 ? loc->next : loc->prev) { + if (!index) { + go_history(ses, loc); + break; + } + + index += index > 0 ? -1 : 1; + } +} + +static void +js_location_toString(struct SEE_interpreter *interp, struct SEE_object *self, + struct SEE_object *thisobj, int argc, struct SEE_value **argv, + struct SEE_value *res) +{ + struct global_object *g = (struct global_object *)interp; + struct view_state *vs = g->win->vs; + unsigned char *string = get_uri_string(vs->uri, URI_ORIGINAL); + struct SEE_string *str = string_to_SEE_string(interp, string); + + mem_free_if(string); + checktime(interp); + + SEE_SET_STRING(res, str); +} + +static void +location_get(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p, struct SEE_value *res) +{ + struct js_location_object *loc = (struct js_location_object *)o; + + checktime(interp); + if (p == s_toString || p == s_toLocaleString) { + SEE_SET_OBJECT(res, loc->toString); + } else if (p == s_href) { + struct global_object *g = (struct global_object *)interp; + struct view_state *vs = g->win->vs; + unsigned char *string = get_uri_string(vs->uri, URI_ORIGINAL); + struct SEE_string *str = string_to_SEE_string(interp, string); + + mem_free_if(string); + SEE_SET_STRING(res, str); + } else { + SEE_SET_UNDEFINED(res); + } +} + +static void +location_put(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p, struct SEE_value *val, int attr) +{ + checktime(interp); + if (p == s_href) { + struct global_object *g = (struct global_object *)interp; + struct view_state *vs = g->win->vs; + struct document_view *doc_view = vs->doc_view; + unsigned char *url = SEE_value_to_unsigned_char(interp, val); + + location_goto(doc_view, url); + mem_free(url); + } +} + +static int +location_hasproperty(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p) +{ + checktime(interp); + if (p == s_toString || p == s_toLocaleString || p == s_href) + return 1; + return 0; +} + +static int +location_canput(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p) +{ + checktime(interp); + if (p == s_href) + return 1; + return 0; +} + +void +init_js_history_object(struct ecmascript_interpreter *interpreter) +{ + struct global_object *g = interpreter->backend_data; + struct SEE_interpreter *interp = &g->interp; + struct SEE_value v; + struct js_history_object *history = SEE_NEW(interp, + struct js_history_object); + + history->object.objectclass = &js_history_object_class; + history->object.objectclass->Class = s_history; + history->object.Prototype = NULL; + + SEE_SET_OBJECT(&v, (struct SEE_object *)history); + SEE_OBJECT_PUT(interp, interp->Global, s_history, &v, 0); + + history->back = SEE_cfunction_make(interp, js_history_back, s_back, 0); + history->forward = SEE_cfunction_make(interp, js_history_forward, s_forward, 0); + history->go = SEE_cfunction_make(interp, js_history_go, s_go, 1); +} + +void +init_js_location_object(struct ecmascript_interpreter *interpreter) +{ + struct global_object *g = interpreter->backend_data; + struct SEE_interpreter *interp = &g->interp; + struct SEE_value v; + struct js_location_object *loc = SEE_NEW(interp, + struct js_location_object); + + loc->object.objectclass = &js_location_object_class; + loc->object.objectclass->Class = s_location; + loc->object.Prototype = NULL; + + SEE_SET_OBJECT(&v, (struct SEE_object *)loc); + SEE_OBJECT_PUT(interp, interp->Global, s_location, &v, 0); + + loc->toString = SEE_cfunction_make(interp, js_location_toString, s_toString, 0); +} diff --git a/src/ecmascript/see/location.h b/src/ecmascript/see/location.h new file mode 100644 index 000000000..9a4c096e4 --- /dev/null +++ b/src/ecmascript/see/location.h @@ -0,0 +1,9 @@ +#ifndef EL__ECMASCRIPT_SEE_LOCATION_H +#define EL__ECMASCRIPT_SEE_LOCATION_H + +struct ecmascript_interpreter; + +void init_js_history_object(struct ecmascript_interpreter *); +void init_js_location_object(struct ecmascript_interpreter *); + +#endif diff --git a/src/ecmascript/see/navigator.c b/src/ecmascript/see/navigator.c new file mode 100644 index 000000000..52b600e9d --- /dev/null +++ b/src/ecmascript/see/navigator.c @@ -0,0 +1,150 @@ +/* The SEE navigator objects implementation. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "elinks.h" + +#include + +#include "bfu/dialog.h" +#include "cache/cache.h" +#include "cookies/cookies.h" +#include "dialogs/menu.h" +#include "dialogs/status.h" +#include "document/html/frames.h" +#include "document/document.h" +#include "document/forms.h" +#include "document/view.h" +#include "ecmascript/ecmascript.h" +#include "ecmascript/see/input.h" +#include "ecmascript/see/navigator.h" +#include "ecmascript/see/strings.h" +#include "ecmascript/see/window.h" +#include "intl/gettext/libintl.h" +#include "main/select.h" +#include "osdep/newwin.h" +#include "osdep/sysname.h" +#include "protocol/http/http.h" +#include "protocol/uri.h" +#include "session/history.h" +#include "session/location.h" +#include "session/session.h" +#include "session/task.h" +#include "terminal/tab.h" +#include "terminal/terminal.h" +#include "util/conv.h" +#include "util/memory.h" +#include "util/string.h" +#include "viewer/text/draw.h" +#include "viewer/text/form.h" +#include "viewer/text/link.h" +#include "viewer/text/vs.h" + +static void navigator_get(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *); +static int navigator_hasproperty(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *); + +struct SEE_objectclass js_navigator_object_class = { + NULL, + navigator_get, + SEE_no_put, + SEE_no_canput, + navigator_hasproperty, + SEE_no_delete, + SEE_no_defaultvalue, + NULL, + NULL, + NULL, + NULL +}; + +static void +navigator_get(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p, struct SEE_value *res) +{ + struct SEE_string *str; + + checktime(interp); + SEE_SET_UNDEFINED(res); + if (p == s_appCodeName) { + SEE_SET_STRING(res, s_Mozilla); + } else if (p == s_appName) { + SEE_SET_STRING(res, s_ELinks_); + } else if (p == s_appVersion) { + str = string_to_SEE_string(interp, VERSION); + SEE_SET_STRING(res, str); + } else if (p == s_language) { +#ifdef CONFIG_NLS + if (get_opt_bool("protocol.http.accept_ui_language")) { + str = string_to_SEE_string(interp, + language_to_iso639(current_language)); + SEE_SET_STRING(res, str); + } +#endif + } else if (p == s_platform) { + str = string_to_SEE_string(interp, system_name); + SEE_SET_STRING(res, str); + } else if (p == s_userAgent) { + /* FIXME: Code duplication. */ + unsigned char *optstr = get_opt_str("protocol.http.user_agent"); + + if (*optstr && strcmp(optstr, " ")) { + unsigned char *ustr, ts[64] = ""; + static unsigned char custr[256]; + + if (!list_empty(terminals)) { + unsigned int tslen = 0; + struct terminal *term = terminals.prev; + + ulongcat(ts, &tslen, term->width, 3, 0); + ts[tslen++] = 'x'; + ulongcat(ts, &tslen, term->height, 3, 0); + } + ustr = subst_user_agent(optstr, VERSION_STRING, system_name, ts); + + if (ustr) { + safe_strncpy(custr, ustr, 256); + mem_free(ustr); + str = string_to_SEE_string(interp, custr); + SEE_SET_STRING(res, str); + } + } + } +} + + +static int +navigator_hasproperty(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p) +{ + checktime(interp); + if (p == s_appCodeName || p == s_appName || p == s_appVersion + || p == s_language || p == s_platform || p == s_userAgent) + return 1; + return 0; +} + + + +void +init_js_navigator_object(struct ecmascript_interpreter *interpreter) +{ + struct global_object *g = interpreter->backend_data; + struct SEE_interpreter *interp = &g->interp; + struct SEE_value v; + struct SEE_object *navigator; + + navigator = SEE_NEW(interp, struct SEE_object); + + navigator->objectclass = &js_navigator_object_class; + navigator->objectclass->Class = s_navigator; + navigator->Prototype = NULL; + + SEE_SET_OBJECT(&v, navigator); + SEE_OBJECT_PUT(interp, interp->Global, s_navigator, &v, 0); +} diff --git a/src/ecmascript/see/navigator.h b/src/ecmascript/see/navigator.h new file mode 100644 index 000000000..d5411acaa --- /dev/null +++ b/src/ecmascript/see/navigator.h @@ -0,0 +1,8 @@ +#ifndef EL__ECMASCRIPT_SEE_NAVIGATOR_H +#define EL__ECMASCRIPT_SEE_NAVIGATOR_H + +struct ecmascript_interpreter; + +void init_js_navigator_object(struct ecmascript_interpreter *); + +#endif diff --git a/src/ecmascript/see/strings.c b/src/ecmascript/see/strings.c new file mode 100644 index 000000000..a42d34ea7 --- /dev/null +++ b/src/ecmascript/see/strings.c @@ -0,0 +1,379 @@ +#include + +struct SEE_string *s_window; +struct SEE_string *s_closed; +struct SEE_string *s_parent; +struct SEE_string *s_self; +struct SEE_string *s_top; +struct SEE_string *s_alert; +struct SEE_string *s_open; + +struct SEE_string *s_menubar; + +struct SEE_string *s_statusbar; +struct SEE_string *s_visible; + +struct SEE_string *s_navigator; +struct SEE_string *s_appCodeName; +struct SEE_string *s_appName; +struct SEE_string *s_appVersion; +struct SEE_string *s_language; +struct SEE_string *s_platform; +struct SEE_string *s_userAgent; + +struct SEE_string *s_history; +struct SEE_string *s_back; +struct SEE_string *s_forward; +struct SEE_string *s_go; + +struct SEE_string *s_location; +struct SEE_string *s_href; +struct SEE_string *s_toString; +struct SEE_string *s_toLocaleString; + +struct SEE_string *s_input; +struct SEE_string *s_accessKey; +struct SEE_string *s_alt; +struct SEE_string *s_checked; +struct SEE_string *s_defaultChecked; +struct SEE_string *s_defaultValue; +struct SEE_string *s_disabled; +struct SEE_string *s_form; +struct SEE_string *s_maxLength; +struct SEE_string *s_name; +struct SEE_string *s_readonly; +struct SEE_string *s_size; +struct SEE_string *s_src; +struct SEE_string *s_tabindex; +struct SEE_string *s_type; +struct SEE_string *s_value; +struct SEE_string *s_blur; +struct SEE_string *s_click; +struct SEE_string *s_focus; +struct SEE_string *s_select; + +struct SEE_string *s_elements; +struct SEE_string *s_item; +struct SEE_string *s_namedItem; +struct SEE_string *s_length; + +struct SEE_string *s_action; +struct SEE_string *s_encoding; +struct SEE_string *s_method; +struct SEE_string *s_target; +struct SEE_string *s_reset; +struct SEE_string *s_submit; + +struct SEE_string *s_forms; + +struct SEE_string *s_document; +struct SEE_string *s_referrer; +struct SEE_string *s_title; +struct SEE_string *s_url; +struct SEE_string *s_write; + +struct SEE_string *s_Mozilla; +struct SEE_string *s_ELinks_; +struct SEE_string *s_cookie; + +struct SEE_string *s_GET; +struct SEE_string *s_POST; +struct SEE_string *s_application_; +struct SEE_string *s_multipart_; +struct SEE_string *s_textplain; + +struct SEE_string *s_text; +struct SEE_string *s_password; +struct SEE_string *s_file; +struct SEE_string *s_checkbox; +struct SEE_string *s_radio; +struct SEE_string *s_image; +struct SEE_string *s_button; +struct SEE_string *s_hidden; + +struct SEE_string *s_timeout; + +void +init_intern_strings(void) +{ + static SEE_char_t SA_window[] = {'w','i','n','d','o','w'}; + static struct SEE_string S_window = SEE_STRING_DECL(SA_window); + static SEE_char_t SA_closed[] = {'c','l','o','s','e','d'}; + static struct SEE_string S_closed = SEE_STRING_DECL(SA_closed); + static SEE_char_t SA_parent[] = {'p','a','r','e','n','t'}; + static struct SEE_string S_parent = SEE_STRING_DECL(SA_parent); + static SEE_char_t SA_self[] = {'s','e','l','f'}; + static struct SEE_string S_self = SEE_STRING_DECL(SA_self); + static SEE_char_t SA_top[] = {'t','o','p'}; + static struct SEE_string S_top = SEE_STRING_DECL(SA_top); + static SEE_char_t SA_alert[] ={'a','l','e','r','t'}; + static struct SEE_string S_alert = SEE_STRING_DECL(SA_alert); + static SEE_char_t SA_open[] ={'o','p','e','n'}; + static struct SEE_string S_open = SEE_STRING_DECL(SA_open); + + static SEE_char_t SA_menubar[] = {'m','e','n','u','b','a','r'}; + static struct SEE_string S_menubar = SEE_STRING_DECL(SA_menubar); + + static SEE_char_t SA_statusbar[] = {'s','t','a','t','u','s','b','a','r'}; + static struct SEE_string S_statusbar = SEE_STRING_DECL(SA_statusbar); + static SEE_char_t SA_visible[] = {'v','i','s','i','b','l','e'}; + static struct SEE_string S_visible = SEE_STRING_DECL(SA_visible); + + static SEE_char_t SA_navigator[] ={'n','a','v','i','g','a','t','o','r'}; + static struct SEE_string S_navigator = SEE_STRING_DECL(SA_navigator); + static SEE_char_t SA_appCodeName[] ={'a','p','p','C','o','d','e','N','a','m','e'}; + static struct SEE_string S_appCodeName = SEE_STRING_DECL(SA_appCodeName); + static SEE_char_t SA_appName[] ={'a','p','p','N','a','m','e'}; + static struct SEE_string S_appName = SEE_STRING_DECL(SA_appName); + static SEE_char_t SA_appVersion[] ={'a','p','p','V','e','r','s','i','o','n'}; + static struct SEE_string S_appVersion = SEE_STRING_DECL(SA_appVersion); + static SEE_char_t SA_language[] ={'l','a','n','g','u','a','g','e'}; + static struct SEE_string S_language = SEE_STRING_DECL(SA_language); + static SEE_char_t SA_platform[] ={'p','l','a','t','f','o','r','m'}; + static struct SEE_string S_platform = SEE_STRING_DECL(SA_platform); + static SEE_char_t SA_userAgent[] ={'u','s','e','r','A','g','e','n','t'}; + static struct SEE_string S_userAgent = SEE_STRING_DECL(SA_userAgent); + + static SEE_char_t SA_history[] ={'h','i','s','t','o','r','y'}; + static struct SEE_string S_history = SEE_STRING_DECL(SA_history); + static SEE_char_t SA_back[] ={'b','a','c','k'}; + static struct SEE_string S_back = SEE_STRING_DECL(SA_back); + static SEE_char_t SA_forward[] ={'f','o','r','w','a','r','d'}; + static struct SEE_string S_forward = SEE_STRING_DECL(SA_forward); + static SEE_char_t SA_go[] ={'g','o'}; + static struct SEE_string S_go = SEE_STRING_DECL(SA_go); + + static SEE_char_t SA_location[] ={'l','o','c','a','t','i','o','n'}; + static struct SEE_string S_location = SEE_STRING_DECL(SA_location); + static SEE_char_t SA_href[] ={'h','r','e','f'}; + static struct SEE_string S_href = SEE_STRING_DECL(SA_href); + static SEE_char_t SA_toString[] ={'t','o','S','t','r','i','n','g'}; + static struct SEE_string S_toString = SEE_STRING_DECL(SA_toString); + static SEE_char_t SA_toLocaleString[] ={'t','o','L','o','c','a','l','e','S','t','r','i','n','g'}; + static struct SEE_string S_toLocaleString = SEE_STRING_DECL(SA_toLocaleString); + + static SEE_char_t SA_input[] ={'i','n','p','u','t'}; + static struct SEE_string S_input = SEE_STRING_DECL(SA_input); + static SEE_char_t SA_accessKey[] ={'a','c','c','e','s','s','K','e','y'}; + static struct SEE_string S_accessKey = SEE_STRING_DECL(SA_accessKey); + static SEE_char_t SA_alt[] ={'a','l','t'}; + static struct SEE_string S_alt = SEE_STRING_DECL(SA_alt); + static SEE_char_t SA_checked[] ={'c','h','e','c','k','e','d'}; + static struct SEE_string S_checked = SEE_STRING_DECL(SA_checked); + static SEE_char_t SA_defaultChecked[] ={'d','e','f','a','u','l','t','C','h','e','c','k','e','d'}; + static struct SEE_string S_defaultChecked = SEE_STRING_DECL(SA_defaultChecked); + static SEE_char_t SA_defaultValue[] ={'d','e','f','a','u','l','t','V','a','l','u','e'}; + static struct SEE_string S_defaultValue = SEE_STRING_DECL(SA_defaultValue); + static SEE_char_t SA_disabled[] ={'d','i','s','a','b','l','e','d'}; + static struct SEE_string S_disabled = SEE_STRING_DECL(SA_disabled); + static SEE_char_t SA_form[] ={'f','o','r','m'}; + static struct SEE_string S_form = SEE_STRING_DECL(SA_form); + static SEE_char_t SA_maxLength[] ={'m','a','x','L','e','n','g','t','h'}; + static struct SEE_string S_maxLength = SEE_STRING_DECL(SA_maxLength); + static SEE_char_t SA_name[] ={'n','a','m','e'}; + static struct SEE_string S_name = SEE_STRING_DECL(SA_name); + static SEE_char_t SA_readonly[] ={'r','e','a','d','o','n','l','y'}; + static struct SEE_string S_readonly = SEE_STRING_DECL(SA_readonly); + static SEE_char_t SA_size[] ={'s','i','z','e'}; + static struct SEE_string S_size = SEE_STRING_DECL(SA_size); + static SEE_char_t SA_src[] ={'s','r','c'}; + static struct SEE_string S_src = SEE_STRING_DECL(SA_src); + static SEE_char_t SA_tabindex[] ={'t','a','b','i','n','d','e','x'}; + static struct SEE_string S_tabindex = SEE_STRING_DECL(SA_tabindex); + static SEE_char_t SA_type[] ={'t','y','p','e'}; + static struct SEE_string S_type = SEE_STRING_DECL(SA_type); + static SEE_char_t SA_value[] ={'v','a','l','u','e'}; + static struct SEE_string S_value = SEE_STRING_DECL(SA_value); + static SEE_char_t SA_blur[] ={'b','l','u','r'}; + static struct SEE_string S_blur = SEE_STRING_DECL(SA_blur); + static SEE_char_t SA_click[] ={'c','l','i','c','k'}; + static struct SEE_string S_click = SEE_STRING_DECL(SA_click); + static SEE_char_t SA_focus[] ={'f','o','c','u','s'}; + static struct SEE_string S_focus = SEE_STRING_DECL(SA_focus); + static SEE_char_t SA_select[] ={'s','e','l','e','c','t'}; + static struct SEE_string S_select = SEE_STRING_DECL(SA_select); + + static SEE_char_t SA_elements[] ={'e','l','e','m','e','n','t','s'}; + static struct SEE_string S_elements = SEE_STRING_DECL(SA_elements); + static SEE_char_t SA_item[] ={'i','t','e','m'}; + static struct SEE_string S_item = SEE_STRING_DECL(SA_item); + static SEE_char_t SA_namedItem[] ={'n','a','m','e','d','I','t','e','m'}; + static struct SEE_string S_namedItem = SEE_STRING_DECL(SA_namedItem); + static SEE_char_t SA_length[] ={'l','e','n','g','t','h'}; + static struct SEE_string S_length = SEE_STRING_DECL(SA_length); + + static SEE_char_t SA_action[] ={'a','c','t','i','o','n'}; + static struct SEE_string S_action = SEE_STRING_DECL(SA_action); + static SEE_char_t SA_encoding[] ={'e','n','c','o','d','i','g'}; + static struct SEE_string S_encoding = SEE_STRING_DECL(SA_encoding); + static SEE_char_t SA_method[] ={'m','e','t','h','o','d'}; + static struct SEE_string S_method = SEE_STRING_DECL(SA_method); + static SEE_char_t SA_target[] ={'t','a','r','g','e','t'}; + static struct SEE_string S_target = SEE_STRING_DECL(SA_target); + static SEE_char_t SA_reset[] ={'r','e','s','e','t'}; + static struct SEE_string S_reset = SEE_STRING_DECL(SA_reset); + static SEE_char_t SA_submit[] ={'s','u','b','m','i','t'}; + static struct SEE_string S_submit = SEE_STRING_DECL(SA_submit); + + static SEE_char_t SA_forms[] ={'f','o','r','m','s'}; + static struct SEE_string S_forms = SEE_STRING_DECL(SA_forms); + + static SEE_char_t SA_document[] = {'d','o','c','u','m','e','n','t'}; + static struct SEE_string S_document = SEE_STRING_DECL(SA_document); + static SEE_char_t SA_referrer[] ={'r','e','f','e','r','r','e','r'}; + static struct SEE_string S_referrer = SEE_STRING_DECL(SA_referrer); + static SEE_char_t SA_title[] ={'t','i','t','l','e'}; + static struct SEE_string S_title = SEE_STRING_DECL(SA_title); + static SEE_char_t SA_url[] ={'u','r','l'}; + static struct SEE_string S_url = SEE_STRING_DECL(SA_url); + static SEE_char_t SA_write[] = {'w','r','i','t','e'}; + static struct SEE_string S_write = SEE_STRING_DECL(SA_write); + + static SEE_char_t SA_Mozilla[] = {'M','o','z','i','l','l','a'}; + static struct SEE_string S_Mozilla = SEE_STRING_DECL(SA_Mozilla); + static SEE_char_t SA_ELinks_[] = {'E','L','i','n','k','s',' ','(', + 'r','o','u','g','h','l','y',' ','c','o','m','p','a','t','i','b','l','e', + ' ','w','i','t','h',' ','N','e','t','s','c','a','p','e',' ', + 'N','a','v','i','g','a','t','o','r',',',' ','M','o','z','i','l','l','a', + ' ','a','n','d',' ','M','i','c','r','o','s','o','f','t',' ', + 'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r',')'}; + static struct SEE_string S_ELinks_ = SEE_STRING_DECL(SA_ELinks_); + + static SEE_char_t SA_cookie[] = {'c','o','o','k','i','e'}; + static struct SEE_string S_cookie = SEE_STRING_DECL(SA_cookie); + + static SEE_char_t SA_GET[] = {'G','E','T'}; + static struct SEE_string S_GET = SEE_STRING_DECL(SA_GET); + static SEE_char_t SA_POST[] = {'P','O','S','T'}; + static struct SEE_string S_POST = SEE_STRING_DECL(SA_POST); + + static SEE_char_t SA_application_[] = {'a','p','p','l','i','c','a','t', + 'i','o','n','/','x','-','w','w','w','-','f','o','r','m','-','u','r','l', + 'e','n','c','o','d','e','d'}; + static struct SEE_string S_application_ = SEE_STRING_DECL(SA_application_); + static SEE_char_t SA_multipart_[] = {'m','u','l','t','i','p','a','r','t','/', + 'f','o','r','m','-','d','a','t','a'}; + static struct SEE_string S_multipart_ = SEE_STRING_DECL(SA_multipart_); + static SEE_char_t SA_textplain[] = {'t','e','x','t','/','p','l','a','i','n'}; + static struct SEE_string S_textplain = SEE_STRING_DECL(SA_textplain); + + static SEE_char_t SA_text[] = {'t','e','x','t'}; + static struct SEE_string S_text = SEE_STRING_DECL(SA_text); + + static SEE_char_t SA_password[] = {'p','a','s','s','w','o','r','d'}; + static struct SEE_string S_password = SEE_STRING_DECL(SA_password); + + static SEE_char_t SA_file[] = {'f','i','l','e'}; + static struct SEE_string S_file = SEE_STRING_DECL(SA_file); + + static SEE_char_t SA_checkbox[] = {'c','h','e','c','k','b','o','x'}; + static struct SEE_string S_checkbox = SEE_STRING_DECL(SA_checkbox); + + static SEE_char_t SA_radio[] = {'r','a','d','i','o'}; + static struct SEE_string S_radio = SEE_STRING_DECL(SA_radio); + + static SEE_char_t SA_image[] = {'i','m','a','g','e'}; + static struct SEE_string S_image = SEE_STRING_DECL(SA_image); + + static SEE_char_t SA_button[] = {'b','u','t','t','o','n'}; + static struct SEE_string S_button = SEE_STRING_DECL(SA_button); + + static SEE_char_t SA_hidden[] = {'h','i','d','d','e','n'}; + static struct SEE_string S_hidden = SEE_STRING_DECL(SA_hidden); + + static SEE_char_t SA_timeout[] = {'t','i','m','e','o','u','t'}; + static struct SEE_string S_timeout = SEE_STRING_DECL(SA_timeout); + + SEE_intern_global(s_window = &S_window); + SEE_intern_global(s_closed = &S_closed); + SEE_intern_global(s_parent = &S_parent); + SEE_intern_global(s_self = &S_self); + SEE_intern_global(s_top = &S_top); + SEE_intern_global(s_alert = &S_alert); + SEE_intern_global(s_open = &S_open); + + SEE_intern_global(s_menubar = &S_menubar); + SEE_intern_global(s_statusbar = &S_statusbar); + SEE_intern_global(s_visible = &S_visible); + + SEE_intern_global(s_navigator = &S_navigator); + SEE_intern_global(s_appCodeName = &S_appCodeName); + SEE_intern_global(s_appName = &S_appName); + SEE_intern_global(s_appVersion = &S_appVersion); + SEE_intern_global(s_language = &S_language); + SEE_intern_global(s_platform = &S_platform); + SEE_intern_global(s_userAgent = &S_userAgent); + + SEE_intern_global(s_history = &S_history); + SEE_intern_global(s_back = &S_back); + SEE_intern_global(s_forward = &S_forward); + SEE_intern_global(s_go = &S_go); + + SEE_intern_global(s_location = &S_location); + SEE_intern_global(s_href = &S_href); + SEE_intern_global(s_toString = &S_toString); + SEE_intern_global(s_toLocaleString = &S_toLocaleString); + + SEE_intern_global(s_input = &S_input); + SEE_intern_global(s_accessKey = &S_accessKey); + SEE_intern_global(s_alt = &S_alt); + SEE_intern_global(s_checked = &S_checked); + SEE_intern_global(s_defaultChecked = &S_defaultChecked); + SEE_intern_global(s_defaultValue = &S_defaultValue); + SEE_intern_global(s_disabled = &S_disabled); + SEE_intern_global(s_form = &S_form); + SEE_intern_global(s_maxLength = &S_maxLength); + SEE_intern_global(s_name = &S_name); + SEE_intern_global(s_readonly = &S_readonly); + SEE_intern_global(s_size = &S_size); + SEE_intern_global(s_src = &S_src); + SEE_intern_global(s_tabindex = &S_tabindex); + SEE_intern_global(s_type = &S_type); + SEE_intern_global(s_value = &S_value); + SEE_intern_global(s_blur = &S_blur); + SEE_intern_global(s_click = &S_click); + SEE_intern_global(s_focus = &S_focus); + SEE_intern_global(s_select = &S_select); + + SEE_intern_global(s_elements = &S_elements); + SEE_intern_global(s_item = &S_item); + SEE_intern_global(s_namedItem = &S_namedItem); + SEE_intern_global(s_length = &S_length); + + SEE_intern_global(s_action = &S_action); + SEE_intern_global(s_encoding = &S_encoding); + SEE_intern_global(s_method = &S_method); + SEE_intern_global(s_target = &S_target); + SEE_intern_global(s_reset = &S_reset); + SEE_intern_global(s_submit = &S_submit); + + SEE_intern_global(s_forms = &S_forms); + + SEE_intern_global(s_document = &S_document); + SEE_intern_global(s_referrer = &S_referrer); + SEE_intern_global(s_title = &S_title); + SEE_intern_global(s_url = &S_url); + SEE_intern_global(s_write = &S_write); + + SEE_intern_global(s_Mozilla = &S_Mozilla); + SEE_intern_global(s_ELinks_ = &S_ELinks_); + SEE_intern_global(s_cookie = &S_cookie); + + SEE_intern_global(s_GET = &S_GET); + SEE_intern_global(s_POST = &S_POST); + + SEE_intern_global(s_application_ = &S_application_); + SEE_intern_global(s_multipart_ = &S_multipart_); + SEE_intern_global(s_textplain = &S_textplain); + + SEE_intern_global(s_text = &S_text); + SEE_intern_global(s_password = &S_password); + SEE_intern_global(s_file = &S_file); + SEE_intern_global(s_checkbox = &S_checkbox); + SEE_intern_global(s_radio = &S_radio); + SEE_intern_global(s_image = &S_image); + SEE_intern_global(s_button = &S_button); + SEE_intern_global(s_hidden = &S_hidden); + + SEE_intern_global(s_timeout = &S_timeout); +} diff --git a/src/ecmascript/see/strings.h b/src/ecmascript/see/strings.h new file mode 100644 index 000000000..75f254a92 --- /dev/null +++ b/src/ecmascript/see/strings.h @@ -0,0 +1,101 @@ + +#ifndef EL__ECMASCRIPT_SEE_STRINGS_H +#define EL__ECMASCRIPT_SEE_STRINGS_H + +#include + +void init_intern_strings(void); + +extern struct SEE_string *s_window; +extern struct SEE_string *s_closed; +extern struct SEE_string *s_parent; +extern struct SEE_string *s_self; +extern struct SEE_string *s_top; +extern struct SEE_string *s_alert; +extern struct SEE_string *s_open; + +extern struct SEE_string *s_menubar; + +extern struct SEE_string *s_statusbar; +extern struct SEE_string *s_visible; + +extern struct SEE_string *s_navigator; +extern struct SEE_string *s_appCodeName; +extern struct SEE_string *s_appName; +extern struct SEE_string *s_appVersion; +extern struct SEE_string *s_language; +extern struct SEE_string *s_platform; +extern struct SEE_string *s_userAgent; + +extern struct SEE_string *s_history; +extern struct SEE_string *s_back; +extern struct SEE_string *s_forward; +extern struct SEE_string *s_go; + +extern struct SEE_string *s_location; +extern struct SEE_string *s_href; +extern struct SEE_string *s_toString; +extern struct SEE_string *s_toLocaleString; + +extern struct SEE_string *s_input; +extern struct SEE_string *s_accessKey; +extern struct SEE_string *s_alt; +extern struct SEE_string *s_checked; +extern struct SEE_string *s_defaultChecked; +extern struct SEE_string *s_defaultValue; +extern struct SEE_string *s_disabled; +extern struct SEE_string *s_form; +extern struct SEE_string *s_maxLength; +extern struct SEE_string *s_name; +extern struct SEE_string *s_readonly; +extern struct SEE_string *s_size; +extern struct SEE_string *s_src; +extern struct SEE_string *s_tabindex; +extern struct SEE_string *s_type; +extern struct SEE_string *s_value; +extern struct SEE_string *s_blur; +extern struct SEE_string *s_click; +extern struct SEE_string *s_focus; +extern struct SEE_string *s_select; + +extern struct SEE_string *s_elements; +extern struct SEE_string *s_item; +extern struct SEE_string *s_namedItem; +extern struct SEE_string *s_length; + +extern struct SEE_string *s_action; +extern struct SEE_string *s_encoding; +extern struct SEE_string *s_method; +extern struct SEE_string *s_target; +extern struct SEE_string *s_reset; +extern struct SEE_string *s_submit; + +extern struct SEE_string *s_forms; + +extern struct SEE_string *s_document; +extern struct SEE_string *s_referrer; +extern struct SEE_string *s_title; +extern struct SEE_string *s_url; +extern struct SEE_string *s_write; + +extern struct SEE_string *s_Mozilla; +extern struct SEE_string *s_ELinks_; +extern struct SEE_string *s_cookie; + +extern struct SEE_string *s_GET; +extern struct SEE_string *s_POST; +extern struct SEE_string *s_application_; +extern struct SEE_string *s_multipart_; +extern struct SEE_string *s_textplain; + +extern struct SEE_string *s_text; +extern struct SEE_string *s_password; +extern struct SEE_string *s_file; +extern struct SEE_string *s_checkbox; +extern struct SEE_string *s_radio; +extern struct SEE_string *s_image; +extern struct SEE_string *s_button; +extern struct SEE_string *s_hidden; + +extern struct SEE_string *s_timeout; +#endif diff --git a/src/ecmascript/see/unibar.c b/src/ecmascript/see/unibar.c new file mode 100644 index 000000000..ecbfb5074 --- /dev/null +++ b/src/ecmascript/see/unibar.c @@ -0,0 +1,206 @@ +/* The SEE location and history objects implementation. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "elinks.h" + +#include + +#include "bfu/dialog.h" +#include "cache/cache.h" +#include "cookies/cookies.h" +#include "dialogs/menu.h" +#include "dialogs/status.h" +#include "document/html/frames.h" +#include "document/document.h" +#include "document/forms.h" +#include "document/view.h" +#include "ecmascript/ecmascript.h" +#include "ecmascript/see/input.h" +#include "ecmascript/see/strings.h" +#include "ecmascript/see/unibar.h" +#include "ecmascript/see/window.h" +#include "intl/gettext/libintl.h" +#include "main/select.h" +#include "osdep/newwin.h" +#include "osdep/sysname.h" +#include "protocol/http/http.h" +#include "protocol/uri.h" +#include "session/history.h" +#include "session/location.h" +#include "session/session.h" +#include "session/task.h" +#include "terminal/tab.h" +#include "terminal/terminal.h" +#include "util/conv.h" +#include "util/memory.h" +#include "util/string.h" +#include "viewer/text/draw.h" +#include "viewer/text/form.h" +#include "viewer/text/link.h" +#include "viewer/text/vs.h" + +static void unibar_get(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *); +static void unibar_put(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *, int); +static int unibar_canput(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *); +static int unibar_hasproperty(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *); + +struct js_unibar_object { + struct SEE_object object; + unsigned char bar; +}; + +struct SEE_objectclass js_menubar_object_class = { + NULL, + unibar_get, + unibar_put, + unibar_canput, + unibar_hasproperty, + SEE_no_delete, + SEE_no_defaultvalue, + NULL, + NULL, + NULL, + NULL +}; + +struct SEE_objectclass js_statusbar_object_class = { + NULL, + unibar_get, + unibar_put, + unibar_canput, + unibar_hasproperty, + SEE_no_delete, + SEE_no_defaultvalue, + NULL, + NULL, + NULL, + NULL +}; + +static void +unibar_get(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p, struct SEE_value *res) +{ + struct global_object *g = (struct global_object *)interp; + struct view_state *vs = g->win->vs; + struct document_view *doc_view = vs->doc_view; + struct session_status *status = &doc_view->session->status; + struct js_unibar_object *obj = (struct js_unibar_object *)o; + unsigned char bar = obj->bar; + + checktime(interp); + if (p == s_visible) { +#define unibar_fetch(bar) \ + SEE_SET_BOOLEAN(res, status->force_show_##bar##_bar >= 0 \ + ? status->force_show_##bar##_bar \ + : status->show_##bar##_bar) + switch (bar) { + case 's': + unibar_fetch(status); + break; + case 't': + unibar_fetch(title); + break; + default: + SEE_SET_BOOLEAN(res, 0); + break; + } +#undef unibar_fetch + return; + } + SEE_SET_UNDEFINED(res); +} + +static void +unibar_put(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p, struct SEE_value *val, int attr) +{ + checktime(interp); + if (p == s_location) { + struct global_object *g = (struct global_object *)interp; + struct view_state *vs = g->win->vs; + struct document_view *doc_view = vs->doc_view; + struct session_status *status = &doc_view->session->status; + struct js_unibar_object *obj = (struct js_unibar_object *)o; + unsigned char bar = obj->bar; + + switch (bar) { + case 's': + status->force_show_status_bar = + SEE_ToUint32(interp, val); + break; + case 't': + status->force_show_title_bar = + SEE_ToUint32(interp, val); + break; + default: + break; + + } + } +} + +static int +unibar_canput(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p) +{ + checktime(interp); + if (p == s_visible) + return 1; + return 0; +} + +static int +unibar_hasproperty(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p) +{ + checktime(interp); + if (p == s_visible) + return 1; + return 0; +} + +void +init_js_menubar_object(struct ecmascript_interpreter *interpreter) +{ + struct global_object *g = interpreter->backend_data; + struct SEE_interpreter *interp = &g->interp; + struct SEE_value v; + struct js_unibar_object *menu; + + menu = SEE_NEW(interp, struct js_unibar_object); + + menu->object.objectclass = &js_menubar_object_class; + menu->object.objectclass->Class = s_menubar; + menu->object.Prototype = NULL; + menu->bar = 't'; + + SEE_SET_OBJECT(&v, (struct SEE_object *)menu); + SEE_OBJECT_PUT(interp, interp->Global, s_menubar, &v, 0); +} + +void +init_js_statusbar_object(struct ecmascript_interpreter *interpreter) +{ + struct global_object *g = interpreter->backend_data; + struct SEE_interpreter *interp = &g->interp; + struct SEE_value v; + struct js_unibar_object *status; + + status = SEE_NEW(interp, struct js_unibar_object); + + status->object.objectclass = &js_statusbar_object_class; + status->object.objectclass->Class = s_statusbar; + status->object.Prototype = NULL; + status->bar = 's'; + + SEE_SET_OBJECT(&v, (struct SEE_object *)status); + SEE_OBJECT_PUT(interp, interp->Global, s_statusbar, &v, 0); +} diff --git a/src/ecmascript/see/unibar.h b/src/ecmascript/see/unibar.h new file mode 100644 index 000000000..7eaf6e763 --- /dev/null +++ b/src/ecmascript/see/unibar.h @@ -0,0 +1,9 @@ +#ifndef EL__ECMASCRIPT_SEE_UNIBAR_H +#define EL__ECMASCRIPT_SEE_UNIBAR_H + +struct emascript_interpreter; + +void init_js_menubar_object(struct ecmascript_interpreter *); +void init_js_statusbar_object(struct ecmascript_interpreter *); + +#endif diff --git a/src/ecmascript/see/window.c b/src/ecmascript/see/window.c new file mode 100644 index 000000000..b8e8b420b --- /dev/null +++ b/src/ecmascript/see/window.c @@ -0,0 +1,371 @@ +/* The SEE window object implementation. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include "elinks.h" + +#include + +#include "bfu/dialog.h" +#include "cache/cache.h" +#include "cookies/cookies.h" +#include "dialogs/menu.h" +#include "dialogs/status.h" +#include "document/html/frames.h" +#include "document/document.h" +#include "document/forms.h" +#include "document/view.h" +#include "ecmascript/ecmascript.h" +#include "ecmascript/see/input.h" +#include "ecmascript/see/strings.h" +#include "ecmascript/see/window.h" +#include "intl/gettext/libintl.h" +#include "main/select.h" +#include "osdep/newwin.h" +#include "osdep/sysname.h" +#include "protocol/http/http.h" +#include "protocol/uri.h" +#include "session/history.h" +#include "session/location.h" +#include "session/session.h" +#include "session/task.h" +#include "terminal/tab.h" +#include "terminal/terminal.h" +#include "util/conv.h" +#include "util/memory.h" +#include "util/string.h" +#include "viewer/text/draw.h" +#include "viewer/text/form.h" +#include "viewer/text/link.h" +#include "viewer/text/vs.h" + +static struct js_window_object *js_get_global_object(void *); +static struct js_window_object *js_try_resolve_frame(struct document_view *, unsigned char *); +static void delayed_open(void *); +static void delayed_goto_uri_frame(void *); +static void window_get(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *); +static void window_put(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *, int); +static int window_canput(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *); +static int window_hasproperty(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *); +static void js_window_alert(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *); +static void js_window_open(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *); + +void location_goto(struct document_view *, unsigned char *); + +struct delayed_open { + struct session *ses; + struct uri *uri; + unsigned char *target; +}; + +struct SEE_objectclass js_window_object_class = { + NULL, + window_get, + window_put, + window_canput, + window_hasproperty, + SEE_no_delete, + SEE_no_defaultvalue, + NULL, + NULL, + NULL, + NULL +}; + +static struct js_window_object * +js_get_global_object(void *data) +{ + struct global_object *g = (struct global_object *)data; + return g->win; +} + +static struct js_window_object * +js_try_resolve_frame(struct document_view *doc_view, unsigned char *id) +{ + struct session *ses = doc_view->session; + struct frame *target; + + assert(ses); + target = ses_find_frame(ses, id); + if (!target) return NULL; + if (target->vs.ecmascript_fragile) + ecmascript_reset_state(&target->vs); + if (!target->vs.ecmascript) return NULL; + return js_get_global_object(target->vs.ecmascript->backend_data); +} + + +static void +delayed_open(void *data) +{ + struct delayed_open *deo = data; + + assert(deo); + open_uri_in_new_tab(deo->ses, deo->uri, 0, 0); + done_uri(deo->uri); + mem_free(deo); +} + +static void +delayed_goto_uri_frame(void *data) +{ + struct delayed_open *deo = data; + + assert(deo); + goto_uri_frame(deo->ses, deo->uri, deo->target, CACHE_MODE_NORMAL); + done_uri(deo->uri); + mem_free(deo); +} + + + +static void +window_get(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p, struct SEE_value *res) +{ + struct js_window_object *win = (struct js_window_object *)o; + struct view_state *vs = win->vs; + + checktime(interp); + if (p == s_closed) { + SEE_SET_BOOLEAN(res, 0); + } else if (p == s_self) { + SEE_SET_OBJECT(res, o); + } else if (p == s_top || p == s_parent) { + struct document_view *doc_view = vs->doc_view; + struct document_view *top_view = doc_view->session->doc_view; + struct js_window_object *newjsframe; + + assert(top_view && top_view->vs); + if (top_view->vs->ecmascript_fragile) + ecmascript_reset_state(top_view->vs); + if (!top_view->vs->ecmascript) { + SEE_SET_UNDEFINED(res); + return; + } + newjsframe = js_get_global_object( + top_view->vs->ecmascript->backend_data); + + /* Keep this unrolled this way. Will have to check document.domain + * JS property. */ + /* Note that this check is perhaps overparanoid. If top windows + * is alien but some other child window is not, we should still + * let the script walk thru. That'd mean moving the check to + * other individual properties in this switch. */ + if (compare_uri(vs->uri, top_view->vs->uri, URI_HOST)) { + SEE_SET_OBJECT(res, (struct SEE_object *)newjsframe); + } + + } else if (p == s_alert) { + SEE_SET_OBJECT(res, win->alert); + } else if (p == s_open) { + SEE_SET_OBJECT(res, win->open); + } else { + unsigned char *frame = SEE_string_to_unsigned_char(p); + struct document_view *doc_view = vs->doc_view; + struct js_window_object *obj = + js_try_resolve_frame(doc_view, frame); + + mem_free_if(frame); + if (obj) { + SEE_SET_OBJECT(res, (struct SEE_object *)obj); + } else { + SEE_SET_UNDEFINED(res); + } + } +} + +static void +window_put(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p, struct SEE_value *val, int attr) +{ + checktime(interp); + if (p == s_location) { + struct js_window_object *win = (struct js_window_object *)o; + struct view_state *vs = win->vs; + struct document_view *doc_view = vs->doc_view; + unsigned char *str = SEE_value_to_unsigned_char(interp, val); + + if (str) { + location_goto(doc_view, str); + mem_free(str); + } + } +} + +static int +window_canput(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p) +{ + checktime(interp); + if (p == s_location) + return 1; + return 0; +} + +static int +window_hasproperty(struct SEE_interpreter *interp, struct SEE_object *o, + struct SEE_string *p) +{ + checktime(interp); + /* all unknown properties return UNDEFINED value */ + return 1; +} + + +static void +js_window_alert(struct SEE_interpreter *interp, struct SEE_object *self, + struct SEE_object *thisobj, int argc, struct SEE_value **argv, + struct SEE_value *res) +{ + struct js_window_object *win = (struct js_window_object *)thisobj; + struct view_state *vs = win->vs; + unsigned char *string; + + checktime(interp); + SEE_SET_BOOLEAN(res, 1); + if (argc < 1) + return; + + string = SEE_value_to_unsigned_char(interp, argv[0]); + if (!string || !*string) + return; + + info_box(vs->doc_view->session->tab->term, MSGBOX_FREE_TEXT, + N_("JavaScript Alert"), ALIGN_CENTER, string); + + +} + +static void +js_window_open(struct SEE_interpreter *interp, struct SEE_object *self, + struct SEE_object *thisobj, int argc, struct SEE_value **argv, + struct SEE_value *res) +{ + struct js_window_object *win = (struct js_window_object*)thisobj; + struct view_state *vs = win->vs; + struct document_view *doc_view = vs->doc_view; + struct session *ses = doc_view->session; + unsigned char *target = ""; + unsigned char *url, *url2; + struct uri *uri; +#if 0 + static time_t ratelimit_start; + static int ratelimit_count; +#endif + checktime(interp); + SEE_SET_UNDEFINED(res); + if (get_opt_bool("ecmascript.block_window_opening")) { +#ifdef CONFIG_LEDS + set_led_value(ses->status.popup_led, 'P'); +#endif + return; + } + + if (argc < 1) return; +#if 0 + /* Ratelimit window opening. Recursive window.open() is very nice. + * We permit at most 20 tabs in 2 seconds. The ratelimiter is very + * rough but shall suffice against the usual cases. */ + + if (!ratelimit_start || time(NULL) - ratelimit_start > 2) { + ratelimit_start = time(NULL); + ratelimit_count = 0; + } else { + ratelimit_count++; + if (ratelimit_count > 20) + return; + } +#endif + url = SEE_value_to_unsigned_char(interp, argv[0]); + if (!url) return; + + /* TODO: Support for window naming and perhaps some window features? */ + + url2 = join_urls(doc_view->document->uri, + trim_chars(url, ' ', 0)); + mem_free(url); + if (!url2) return; + uri = get_uri(url2, 0); + mem_free(url2); + if (!uri) return; + + if (argc > 1) + target = SEE_value_to_unsigned_char(interp, argv[1]); + + if (target && *target && strcasecmp(target, "_blank")) { + struct delayed_open *deo = mem_calloc(1, sizeof(*deo)); + + if (deo) { + deo->ses = ses; + deo->uri = get_uri_reference(uri); + deo->target = target; + register_bottom_half(delayed_goto_uri_frame, deo); + goto end; + } + } + + if (!get_cmd_opt_bool("no-connect") + && !get_cmd_opt_bool("no-home") + && !get_cmd_opt_bool("anonymous") + && can_open_in_new(ses->tab->term)) { + open_uri_in_new_window(ses, uri, NULL, ENV_ANY, + CACHE_MODE_NORMAL, TASK_NONE); + } else { + /* When opening a new tab, we might get rerendered, losing our + * context and triggerring a disaster, so postpone that. */ + struct delayed_open *deo = mem_calloc(1, sizeof(*deo)); + + if (deo) { + deo->ses = ses; + deo->uri = get_uri_reference(uri); + register_bottom_half(delayed_open, deo); + } + } + +end: + done_uri(uri); + +} + + +void +init_js_window_object(struct ecmascript_interpreter *interpreter) +{ + struct global_object *g = interpreter->backend_data; + struct SEE_interpreter *interp = &g->interp; + struct SEE_value v; + + g->win = SEE_NEW(interp, struct js_window_object); + + g->win->object.objectclass = &js_window_object_class; + g->win->object.objectclass->Class = s_window; + g->win->object.Prototype = NULL; + g->win->vs = interpreter->vs; + + SEE_SET_OBJECT(&v, (struct SEE_object *)g->win); + SEE_OBJECT_PUT(interp, interp->Global, s_window, &v, 0); + + g->win->alert = SEE_cfunction_make(interp, js_window_alert, s_alert, 1); + g->win->open = SEE_cfunction_make(interp, js_window_open, s_open, 3); +} + +void +checktime(struct SEE_interpreter *interp) +{ + struct global_object *g = (struct global_object *)interp; + + if (time(NULL) - g->exec_start > g->max_exec_time) { + struct terminal *term = g->win->vs->doc_view->session->tab->term; + /* A killer script! Alert! */ + ecmascript_timeout_dialog(term, g->max_exec_time); + SEE_error_throw_string(interp, interp->Error, s_timeout); + } +} diff --git a/src/ecmascript/see/window.h b/src/ecmascript/see/window.h new file mode 100644 index 000000000..0e52e6518 --- /dev/null +++ b/src/ecmascript/see/window.h @@ -0,0 +1,27 @@ +#ifndef EL__ECMASCRIPT_SEE_WINDOW_H +#define EL__ECMASCRIPT_SEE_WINDOW_H + +struct SEE_object; +struct SEE_interpreter; +struct string; +struct view_state; + + +struct js_window_object { + struct SEE_object object; + struct view_state *vs; + struct SEE_object *alert; + struct SEE_object *open; +}; + +struct global_object { + struct SEE_interpreter interp; + struct js_window_object *win; + int exec_start; + int max_exec_time; +}; + +void init_js_window_object(struct ecmascript_interpreter *); +void checktime(struct SEE_interpreter *interp); + +#endif diff --git a/src/ecmascript/spidermonkey.c b/src/ecmascript/spidermonkey.c index 1fa14e63a..0f21054fe 100644 --- a/src/ecmascript/spidermonkey.c +++ b/src/ecmascript/spidermonkey.c @@ -61,6 +61,76 @@ static JSRuntime *jsrt; +void +ecmascript_init(struct module *module) +{ + spidermonkey_init(); +} + +void +ecmascript_done(struct module *module) +{ + spidermonkey_done(); +} + +struct ecmascript_interpreter * +ecmascript_get_interpreter(struct view_state *vs) +{ + struct ecmascript_interpreter *interpreter; + + assert(vs); + + interpreter = mem_calloc(1, sizeof(*interpreter)); + if (!interpreter) + return NULL; + + interpreter->vs = vs; + init_list(interpreter->onload_snippets); + spidermonkey_get_interpreter(interpreter); + + return interpreter; +} + +void +ecmascript_put_interpreter(struct ecmascript_interpreter *interpreter) +{ + assert(interpreter); + spidermonkey_put_interpreter(interpreter); + free_string_list(&interpreter->onload_snippets); + mem_free(interpreter); +} + +void +ecmascript_eval(struct ecmascript_interpreter *interpreter, + struct string *code) +{ + if (!get_ecmascript_enable()) + return; + assert(interpreter); + spidermonkey_eval(interpreter, code); +} + +unsigned char * +ecmascript_eval_stringback(struct ecmascript_interpreter *interpreter, + struct string *code) +{ + if (!get_ecmascript_enable()) + return NULL; + assert(interpreter); + return spidermonkey_eval_stringback(interpreter, code); +} + +int +ecmascript_eval_boolback(struct ecmascript_interpreter *interpreter, + struct string *code) +{ + if (!get_ecmascript_enable()) + return -1; + assert(interpreter); + return spidermonkey_eval_boolback(interpreter, code); +} + + static void error_reporter(JSContext *ctx, const char *message, JSErrorReport *report) { @@ -123,14 +193,7 @@ safeguard(JSContext *ctx, JSScript *script) struct terminal *term = interpreter->vs->doc_view->session->tab->term; /* A killer script! Alert! */ - info_box(term, MSGBOX_FREE_TEXT, - N_("JavaScript Emergency"), ALIGN_LEFT, - msg_text(term, - N_("A script embedded in the current document was running\n" - "for more than %d seconds. This probably means there is\n" - "a bug in the script and it could have halted the whole\n" - "ELinks, so the script execution was interrupted."), - max_exec_time)); + ecmascript_timeout_dialog(term, max_exec_time); return JS_FALSE; } return JS_TRUE; diff --git a/test/ecmascript/infinite2.html b/test/ecmascript/infinite2.html new file mode 100644 index 000000000..8a9e24c49 --- /dev/null +++ b/test/ecmascript/infinite2.html @@ -0,0 +1,5 @@ +