home *** CD-ROM | disk | FTP | other *** search
- /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * The contents of this file are subject to the Netscape Public License
- * Version 1.0 (the "NPL"); you may not use this file except in
- * compliance with the NPL. You may obtain a copy of the NPL at
- * http://www.mozilla.org/NPL/
- *
- * Software distributed under the NPL is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
- * for the specific language governing rights and limitations under the
- * NPL.
- *
- * The Initial Developer of this code under the NPL is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1998 Netscape Communications Corporation. All Rights
- * Reserved.
- */
- /*
- * JS reflection of the current Navigator URL (Location) object.
- *
- * Brendan Eich, 9/8/95
- */
- #include "lm.h"
- #include "xp.h"
- #include "net.h" /* for URL_Struct */
- #include "shist.h" /* for session history stuff */
- #include "structs.h" /* for MWContext */
- #include "layout.h" /* included via -I../layout */
- #include "mkparse.h" /* included via -I../libnet */
-
- /* NB: these named properties use non-negative slots; code below knows that. */
- /* Non-negative slots are protected by a permissions check; others aren't. */
- enum url_slot {
- URL_HREF, /* the entire URL as a string */
- URL_PROTOCOL, /* protocol:... */
- URL_HOST, /* protocol://host/... */
- URL_HOSTNAME, /* protocol://hostname:... */
- URL_PORT, /* protocol://hostname:port/... */
- URL_PATHNAME, /* protocol://host/pathname[#?...] */
- URL_HASH, /* protocol://host/pathname#hash */
- URL_SEARCH, /* protocol://host/pathname?search */
- URL_TARGET, /* target window or null */
- URL_TEXT, /* text within A container */
- URL_X = -1, /* layout X coordinate */
- URL_Y = -2 /* layout Y coordinate */
- };
-
- static JSPropertySpec url_props[] = {
- {"href", URL_HREF, JSPROP_ENUMERATE},
- {"protocol", URL_PROTOCOL, JSPROP_ENUMERATE},
- {"host", URL_HOST, JSPROP_ENUMERATE},
- {"hostname", URL_HOSTNAME, JSPROP_ENUMERATE},
- {"port", URL_PORT, JSPROP_ENUMERATE},
- {"pathname", URL_PATHNAME, JSPROP_ENUMERATE},
- {"hash", URL_HASH, JSPROP_ENUMERATE},
- {"search", URL_SEARCH, JSPROP_ENUMERATE},
- {"target", URL_TARGET, JSPROP_ENUMERATE},
- {"text", URL_TEXT, JSPROP_ENUMERATE | JSPROP_READONLY},
- {"x", URL_X, JSPROP_ENUMERATE | JSPROP_READONLY},
- {"y", URL_Y, JSPROP_ENUMERATE | JSPROP_READONLY},
- {0}
- };
-
- #define ParseURL(url,part) ((url) ? NET_ParseURL(url,part) : 0)
-
- static JSBool
- url_get_coord(JSContext *cx, JSURL *url, jsint slot, jsval *vp)
- {
- int32 coord;
- LO_AnchorData *anchor_data;
- MWContext *context;
-
- LO_LockLayout();
- context = url->url_decoder->window_context;
- anchor_data = LO_GetLinkByIndex(context, url->layer_id, url->index);
- if (anchor_data && anchor_data->element) {
- switch (slot) {
- case URL_X:
- coord = anchor_data->element->lo_any.x;
- break;
-
- case URL_Y:
- coord = anchor_data->element->lo_any.y;
- break;
-
- default:
- LO_UnlockLayout();
- return JS_FALSE;
- }
-
- *vp = INT_TO_JSVAL(coord);
- LO_UnlockLayout();
- return JS_TRUE;
- }
- *vp = JSVAL_NULL;
- LO_UnlockLayout();
- return JS_TRUE;
- }
-
- extern JSClass lm_url_class;
- extern JSClass lm_location_class;
-
- PR_STATIC_CALLBACK(JSBool)
- url_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
- {
- jsval slot;
- JSURL *url;
- JSString * str;
- char *port;
- const char *cstr, *tmp;
-
- if (!JSVAL_IS_INT(id))
- return JS_TRUE;
-
- slot = JSVAL_TO_INT(id);
- url = JS_GetInstancePrivate(cx, obj, &lm_url_class, NULL);
- if (!url) {
- url = JS_GetInstancePrivate(cx, obj, &lm_location_class, NULL);
- if (!url)
- return JS_TRUE;
- }
-
- str = 0;
- cstr = 0;
-
- switch (slot) {
- case URL_HREF:
- str = url->href;
- break;
-
- case URL_PROTOCOL:
- if (url->href)
- cstr = ParseURL(JS_GetStringBytes(url->href), GET_PROTOCOL_PART);
- break;
-
- case URL_HOST:
- if (url->href)
- cstr = ParseURL(JS_GetStringBytes(url->href), GET_HOST_PART);
- break;
-
- case URL_HOSTNAME:
- if (url->href)
- cstr = ParseURL(JS_GetStringBytes(url->href), GET_HOST_PART);
- if (cstr && (port = XP_STRCHR(cstr, ':')) != 0)
- *port = '\0';
- break;
-
- case URL_PORT:
- if (url->href)
- cstr = ParseURL(JS_GetStringBytes(url->href), GET_HOST_PART);
- if (cstr && (port = XP_STRCHR(cstr, ':')) != 0)
- port++;
- else
- port = "";
- tmp = cstr;
- cstr = JS_strdup(cx, port);
- XP_FREE((void *)tmp);
- break;
-
- case URL_PATHNAME:
- if (url->href)
- cstr = ParseURL(JS_GetStringBytes(url->href), GET_PATH_PART);
- break;
-
- case URL_HASH:
- if (url->href)
- cstr = ParseURL(JS_GetStringBytes(url->href), GET_HASH_PART);
- break;
-
- case URL_SEARCH:
- if (url->href)
- cstr = ParseURL(JS_GetStringBytes(url->href), GET_SEARCH_PART);
- break;
-
- case URL_TARGET:
- if (!url->target) {
- *vp = JSVAL_NULL;
- return JS_TRUE;
- }
- str = url->target;
- break;
-
- case URL_TEXT:
- if (!url->text) {
- *vp = JSVAL_NULL;
- return JS_TRUE;
- }
- str = url->text;
- break;
-
- case URL_X:
- case URL_Y:
- return url_get_coord(cx, url, slot, vp);
-
- default:
- /* Don't mess with user-defined or method properties. */
- return JS_TRUE;
- }
-
- if (!str && cstr)
- str = JS_NewStringCopyZ(cx, cstr);
- if (cstr)
- XP_FREE((char *)cstr);
- if (!str)
- return JS_FALSE;
- *vp = STRING_TO_JSVAL(str);
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(JSBool)
- url_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
- {
- JSURL *url;
- const char *href, *name, *checked_href;
- char *new_href, *prop_name;
- JSBool free_href;
- jsval tmp;
- JSString *str;
- MWContext *context;
- LO_AnchorData *anchor_data;
- JSBool ok;
- jsint slot;
-
- url = JS_GetInstancePrivate(cx, obj, &lm_url_class, NULL);
- if (!url) {
- url = JS_GetInstancePrivate(cx, obj, &lm_location_class, NULL);
- if (!url)
- return JS_TRUE;
- }
-
- /* If the property is setting an event handler we find out now so
- * that we can tell the front end to send the event.
- */
- if (JSVAL_IS_STRING(id)) {
- prop_name = JS_GetStringBytes(JSVAL_TO_STRING(id));
- if (XP_STRCASECMP(prop_name, lm_onClick_str) == 0 ||
- XP_STRCASECMP(prop_name, lm_onMouseDown_str) == 0 ||
- XP_STRCASECMP(prop_name, lm_onMouseOver_str) == 0 ||
- XP_STRCASECMP(prop_name, lm_onMouseOut_str) == 0 ||
- XP_STRCASECMP(prop_name, lm_onMouseUp_str) == 0) {
- context = url->url_decoder->window_context;
- if (context) {
- anchor_data = LO_GetLinkByIndex(context, url->layer_id,
- url->index);
- if (anchor_data)
- anchor_data->event_handler_present = TRUE;
- }
- }
- return JS_TRUE;
- }
-
- XP_ASSERT(JSVAL_IS_INT(id));
- slot = JSVAL_TO_INT(id);
-
- if (slot < 0) {
- /* Don't mess with user-defined or method properties. */
- return JS_TRUE;
- }
-
- if (!JSVAL_IS_STRING(*vp) &&
- !JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp)) {
- return JS_FALSE;
- }
-
- ok = JS_TRUE;
-
- switch (slot) {
- case URL_HREF:
- url->href = JSVAL_TO_STRING(*vp);
- href = JS_GetStringBytes(url->href);
- free_href = JS_FALSE;
- break;
-
- case URL_PROTOCOL:
- case URL_HOST:
- case URL_HOSTNAME:
- case URL_PORT:
- case URL_PATHNAME:
- case URL_HASH:
- case URL_SEARCH:
- /* a component property changed -- recompute href. */
- new_href = NULL;
-
- #define GET_SLOT(aslot, ptmp) { \
- if (aslot == slot) { \
- *(ptmp) = *vp; \
- } else { \
- if (!JS_GetElement(cx, obj, aslot, ptmp)) { \
- if (new_href) XP_FREE(new_href); \
- return JS_FALSE; \
- } \
- } \
- }
-
- #define ADD_SLOT(aslot, separator) { \
- GET_SLOT(aslot, &tmp); \
- name = JS_GetStringBytes(JSVAL_TO_STRING(tmp)); \
- if (*name) { \
- if (separator) StrAllocCat(new_href, separator); \
- StrAllocCat(new_href, name); \
- } \
- }
-
- GET_SLOT(URL_PROTOCOL, &tmp);
- StrAllocCopy(new_href, JS_GetStringBytes(JSVAL_TO_STRING(tmp)));
- if (slot == URL_HOST) {
- ADD_SLOT(URL_HOST, "//");
- } else {
- ADD_SLOT(URL_HOSTNAME, "//");
- ADD_SLOT(URL_PORT, ":");
- }
- ADD_SLOT(URL_PATHNAME, NULL);
- ADD_SLOT(URL_HASH, NULL);
- ADD_SLOT(URL_SEARCH, NULL);
-
- if (!new_href) {
- JS_ReportOutOfMemory(cx);
- return JS_FALSE;
- }
-
- free_href = JS_TRUE;
- href = new_href;
- str = JS_NewStringCopyZ(cx, href);
- if (!str) {
- ok = JS_FALSE;
- goto out;
- }
- url->href = str;
- break;
-
- case URL_TARGET:
- url->target = JSVAL_TO_STRING(*vp);
- if (url->index != URL_NOT_INDEXED) {
- context = url->url_decoder->window_context;
- if (context) {
- anchor_data = LO_GetLinkByIndex(context, url->layer_id,
- url->index);
- if (anchor_data) {
- name = JS_GetStringBytes(url->target);
- if (!lm_CheckWindowName(cx, name))
- return JS_FALSE;
- if (!lm_SaveParamString(cx, &anchor_data->target, name))
- return JS_FALSE;
- }
- }
- }
- /* Note early return, to bypass href update and freeing. */
- return JS_TRUE;
-
- default:
- /* Don't mess with a user-defined property. */
- return ok;
- }
-
- if (url->index != URL_NOT_INDEXED) {
- context = url->url_decoder->window_context;
- if (context) {
- anchor_data = LO_GetLinkByIndex(context, url->layer_id,
- url->index);
- if (anchor_data) {
- checked_href = lm_CheckURL(cx, href, JS_FALSE);
- if (!checked_href ||
- !lm_SaveParamString(cx, &anchor_data->anchor,
- checked_href)) {
- ok = JS_FALSE;
- goto out;
- }
- XP_FREE((char *)checked_href);
- }
- }
- }
-
- out:
- if (free_href && href)
- XP_FREE((char *)href);
- return ok;
- }
-
- PR_STATIC_CALLBACK(void)
- url_finalize(JSContext *cx, JSObject *obj)
- {
- JSURL *url;
- MochaDecoder *decoder;
- MWContext *context;
- LO_AnchorData *anchor_data;
-
- url = JS_GetPrivate(cx, obj);
- if (!url)
- return;
- decoder = url->url_decoder;
- if (url->index != URL_NOT_INDEXED) {
- context = decoder->window_context;
- if (context) {
- LO_LockLayout();
- anchor_data = LO_GetLinkByIndex(context, url->layer_id,
- url->index);
- if (anchor_data && anchor_data->mocha_object == obj)
- anchor_data->mocha_object = NULL;
- LO_UnlockLayout();
- }
- }
- DROP_BACK_COUNT(decoder);
- JS_RemoveRoot(cx, &url->href);
- JS_RemoveRoot(cx, &url->target);
- JS_RemoveRoot(cx, &url->text);
- XP_DELETE(url);
- }
-
- JSClass lm_url_class = {
- "Url", JSCLASS_HAS_PRIVATE,
- JS_PropertyStub, JS_PropertyStub, url_getProperty, url_setProperty,
- JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, url_finalize
- };
-
- PR_STATIC_CALLBACK(JSBool)
- Url(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(JSBool)
- url_toString(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- return url_getProperty(cx, obj, INT_TO_JSVAL(URL_HREF), rval);
- }
-
- static JSFunctionSpec url_methods[] = {
- {lm_toString_str, url_toString, 0},
- {0}
- };
-
- JSURL *
- lm_NewURL(JSContext *cx, MochaDecoder *decoder, LO_AnchorData *anchor_data,
- JSObject *document)
- {
- JSObject *obj;
- JSURL *url;
- JSString *str;
-
- if (!decoder->url_prototype) {
- obj = JS_InitClass(cx, decoder->window_object,
- decoder->event_receiver_prototype, &lm_url_class,
- Url, 0, url_props, NULL, NULL, NULL);
- if (!obj)
- return NULL;
- decoder->url_prototype = obj;
- }
-
- url = JS_malloc(cx, sizeof *url);
- if (!url)
- return NULL;
- XP_BZERO(url, sizeof *url);
-
- obj = JS_NewObject(cx, &lm_url_class, decoder->url_prototype,
- lm_GetOuterObject(decoder));
- if (!obj || !JS_SetPrivate(cx, obj, url)) {
- JS_free(cx, url);
- return NULL;
- }
-
- if (!JS_DefineFunctions(cx, obj, url_methods))
- return NULL;
-
- url->url_decoder = HOLD_BACK_COUNT(decoder);
- url->url_type = FORM_TYPE_NONE;
- url->index = URL_NOT_INDEXED;
- url->url_object = obj;
-
- str = JS_NewStringCopyZ(cx, (char *) anchor_data->anchor);
- if (!str)
- return NULL;
- url->href = str;
- if (!JS_AddNamedRoot(cx, &url->href, "url.href"))
- return NULL;
-
- if (anchor_data->target) {
- str = JS_NewStringCopyZ(cx, (char *) anchor_data->target);
- if (!str)
- return NULL;
- url->target = str;
- }
- if (!JS_AddNamedRoot(cx, &url->target, "url.target"))
- return NULL;
-
- if (anchor_data->element && anchor_data->element->type == LO_TEXT) {
- str = lm_LocalEncodingToStr(decoder->window_context,
- (char *) anchor_data->element->lo_text.text);
- if (!str)
- return NULL;
- url->text = str;
- }
- if (!JS_AddNamedRoot(cx, &url->text, "url.text"))
- return NULL;
-
- return url;
- }
-
- static const char *
- get_url_string(JSContext *cx, JSObject *obj)
- {
- JSURL *url;
- MochaDecoder *decoder;
- MWContext *context;
- History_entry *he;
- const char *url_string;
-
- url = JS_GetInstancePrivate(cx, obj, &lm_location_class, NULL);
- if (!url)
- return NULL;
- decoder = url->url_decoder;
-
- context = decoder->window_context;
- if (!context)
- return NULL;
- he = SHIST_GetCurrent(&context->hist);
- if (he) {
- url_string = he->address;
- if (NET_URL_Type(url_string) == WYSIWYG_TYPE_URL &&
- !(url_string = LM_SkipWysiwygURLPrefix(url_string))) {
- url_string = he->address;
- }
- return url_string;
- }
- return NULL;
- }
-
- /*
- * Top-level window URL object, a reflection of the "Location:" GUI field.
- */
- PR_STATIC_CALLBACK(JSBool)
- loc_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
- {
- JSURL *url;
- MochaDecoder *decoder;
- MWContext *context;
- const char *url_string;
- JSString *str;
-
- if (!JSVAL_IS_INT(id) || JSVAL_TO_INT(id) < 0)
- return JS_TRUE;
-
- url = JS_GetInstancePrivate(cx, obj, &lm_location_class, NULL);
- if (!url)
- return JS_TRUE;
- decoder = url->url_decoder;
-
- context = decoder->window_context;
- if (!context)
- return JS_TRUE;
- if (context->type == MWContextMail ||
- context->type == MWContextNews ||
- context->type == MWContextMailMsg ||
- context->type == MWContextNewsMsg) {
- /*
- * Don't give out the location of a the mail folder to a script
- * embedded in a mail message. Just return the empty string.
- */
- url->href = JSVAL_TO_STRING(JS_GetEmptyStringValue(cx));
- } else {
- /*
- * Only need to check permissions for native getters
- */
- if (!lm_CheckPermissions(cx, obj, JSTARGET_UNIVERSAL_BROWSER_READ))
- return JS_FALSE;
- url_string = get_url_string(cx, obj);
- if (url_string && (!url->href || XP_STRCMP(JS_GetStringBytes(url->href),
- url_string) != 0))
- {
- str = JS_NewStringCopyZ(cx, url_string);
- if (!str)
- return JS_FALSE;
- url->href = str;
- }
- }
- return url_getProperty(cx, obj, id, vp);
- }
-
- void
- lm_ReplaceURL(MWContext *context, URL_Struct *url_struct)
- {
- History_entry *he;
-
- he = SHIST_GetCurrent(&context->hist);
- if (!he)
- return;
- he->history_num = SHIST_GetIndex(&context->hist, he);
- he->replace = TRUE;
- url_struct->history_num = he->history_num;
- }
-
- JSBool
- lm_GetURL(JSContext *cx, MochaDecoder *decoder, URL_Struct *url_struct)
- {
- MWContext *context;
-
- context = decoder->window_context;
- if (!context) {
- NET_FreeURLStruct(url_struct);
- return JS_TRUE;
- }
-
- if (decoder->replace_location) {
- decoder->replace_location = JS_FALSE;
- lm_ReplaceURL(context, url_struct);
- }
- ET_PostGetUrl(context, url_struct);
- return JS_TRUE;
- }
-
- const char *
- lm_CheckURL(JSContext *cx, const char *url_string, JSBool checkFile)
- {
- char *protocol, *absolute;
- JSObject *obj;
- MochaDecoder *decoder;
-
- protocol = NET_ParseURL(url_string, GET_PROTOCOL_PART);
- if (!protocol || *protocol == '\0') {
- lo_TopState *top_state;
-
- obj = JS_GetGlobalObject(cx);
- decoder = JS_GetPrivate(cx, obj);
-
- LO_LockLayout();
- top_state = lo_GetMochaTopState(decoder->window_context);
- if (top_state && top_state->base_url) {
- absolute = NET_MakeAbsoluteURL(top_state->base_url,
- (char *)url_string); /*XXX*/
- /*
- * Temporarily unlock layout so that we don't hold the lock
- * across a call (lm_CheckPermissions) that may result in
- * synchronous event handling.
- */
- LO_UnlockLayout();
- if (!lm_CheckPermissions(cx, obj,
- JSTARGET_UNIVERSAL_BROWSER_READ))
- {
- /* Don't leak information about the url of this page. */
- XP_FREEIF(absolute);
- return NULL;
- }
- LO_LockLayout();
- } else {
- absolute = NULL;
- }
- if (absolute) {
- if (protocol) XP_FREE(protocol);
- protocol = NET_ParseURL(absolute, GET_PROTOCOL_PART);
- }
- LO_UnlockLayout();
- } else {
- absolute = JS_strdup(cx, url_string);
- if (!absolute) {
- XP_FREE(protocol);
- return NULL;
- }
- decoder = NULL;
- }
-
- if (absolute) {
-
- /* Make sure it's a safe URL type. */
- switch (NET_URL_Type(protocol)) {
- case FILE_TYPE_URL:
- if (checkFile) {
- const char *subjectOrigin = lm_GetSubjectOriginURL(cx);
- if (subjectOrigin == NULL) {
- XP_FREE(protocol);
- return NULL;
- }
- if (NET_URL_Type(subjectOrigin) != FILE_TYPE_URL &&
- !lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_FILE_READ))
- {
- XP_FREE(absolute);
- absolute = NULL;
- }
- }
- break;
- case FTP_TYPE_URL:
- case GOPHER_TYPE_URL:
- case HTTP_TYPE_URL:
- case MAILTO_TYPE_URL:
- case NEWS_TYPE_URL:
- case RLOGIN_TYPE_URL:
- case TELNET_TYPE_URL:
- case TN3270_TYPE_URL:
- case WAIS_TYPE_URL:
- case SECURE_HTTP_TYPE_URL:
- case URN_TYPE_URL:
- case NFS_TYPE_URL:
- case MOCHA_TYPE_URL:
- case VIEW_SOURCE_TYPE_URL:
- case NETHELP_TYPE_URL:
- case WYSIWYG_TYPE_URL:
- case LDAP_TYPE_URL:
- #ifdef JAVA
- case MARIMBA_TYPE_URL:
- #endif
- /* These are "safe". */
- break;
- case ABOUT_TYPE_URL:
- if (XP_STRCASECMP(absolute, "about:blank") == 0)
- break;
- if (XP_STRNCASECMP(absolute, "about:pics", 10) == 0)
- break;
- /* these are OK if we are signed */
- if (lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_READ))
- break;
- /* FALL THROUGH */
- default:
- /* All others are naughty. */
- XP_FREE(absolute);
- absolute = NULL;
- break;
- }
- }
-
- if (!absolute) {
- JS_ReportError(cx, "illegal URL method '%s'",
- protocol && *protocol ? protocol : url_string);
- }
- if (protocol)
- XP_FREE(protocol);
- return absolute;
- }
-
- static JSBool
- url_load(JSContext *cx, JSObject *obj, const char *url_string,
- NET_ReloadMethod reload_how)
- {
- JSURL *url;
- URL_Struct *url_struct;
- const char *referer;
-
- url = JS_GetPrivate(cx, obj);
- if (!url)
- return JS_TRUE;
- url_struct = NET_CreateURLStruct(url_string, reload_how);
- if (!url_struct) {
- JS_ReportOutOfMemory(cx);
- return JS_FALSE;
- }
- if (!(referer = lm_GetSubjectOriginURL(cx)) ||
- !(url_struct->referer = JS_strdup(cx, referer))) {
- NET_FreeURLStruct(url_struct);
- return JS_FALSE;
- }
- return lm_GetURL(cx, url->url_decoder, url_struct);
- }
-
- PR_STATIC_CALLBACK(JSBool)
- loc_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
- {
- const char *url_string;
- JSString *str;
- jsval val;
- jsint slot;
- JSURL *url;
-
- if (!JSVAL_IS_INT(id))
- return JS_TRUE;
-
- slot = JSVAL_TO_INT(id);
- /* Setting these properties should not cause a FE_GetURL. */
- if (slot < 0 || slot == URL_TARGET)
- return url_setProperty(cx, obj, id, vp);
-
- /* Make sure vp is a string. */
- if (!JSVAL_IS_STRING(*vp) &&
- !JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp)) {
- return JS_FALSE;
- }
-
- /* Two cases: setting href vs. setting a component property. */
- if (slot == URL_HREF || slot == URL_PROTOCOL) {
- /* Make sure the URL is absolute and sanity-check its protocol. */
- url_string = JS_GetStringBytes(JSVAL_TO_STRING(*vp));
- url_string = lm_CheckURL(cx, url_string, JS_TRUE);
- if (!url_string)
- return JS_FALSE;
- str = JS_NewStringCopyZ(cx, url_string);
- XP_FREE((char *)url_string);
- if (!str)
- return JS_FALSE;
- val = STRING_TO_JSVAL(str);
- vp = &val;
- } else {
- /* Get href from session history before setting a piece of it. */
- if (!loc_getProperty(cx, obj, INT_TO_JSVAL(URL_HREF), &val))
- return JS_FALSE;
- }
-
- /* Set slot's property. */
- if (!url_setProperty(cx, obj, id, vp))
- return JS_FALSE;
-
- url = JS_GetPrivate(cx, obj);
- if (!url)
- return JS_TRUE;
- if (url->href)
- url_string = JS_GetStringBytes(url->href);
- else
- url_string = "";
- return url_load(cx, obj, url_string, NET_DONT_RELOAD);
- }
-
- JSClass lm_location_class = {
- "Location", JSCLASS_HAS_PRIVATE,
- JS_PropertyStub, JS_PropertyStub, loc_getProperty, loc_setProperty,
- JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, url_finalize
- };
-
- PR_STATIC_CALLBACK(JSBool)
- Location(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(JSBool)
- loc_toString(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- return loc_getProperty(cx, obj, INT_TO_JSVAL(URL_HREF), rval);
- }
-
- PR_STATIC_CALLBACK(JSBool)
- loc_assign(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
- {
- JSURL *url;
- jsval v;
- JSObject *locobj;
-
- if (!JS_InstanceOf(cx, obj, &lm_location_class, NULL)) {
- if(!JS_LookupProperty(cx, obj, lm_location_str, &v)) {
- return JS_FALSE;
- }
- if(!JSVAL_IS_OBJECT(v) || !JSVAL_TO_OBJECT(v)) {
- return JS_TRUE;
- }
- locobj = JSVAL_TO_OBJECT(v);
- } else {
- locobj = obj;
- }
- if (!(url = JS_GetInstancePrivate(cx, locobj, &lm_location_class, NULL)))
- return JS_FALSE;
- if (!loc_setProperty(cx, locobj, INT_TO_JSVAL(URL_HREF), vp))
- return JS_FALSE;
- *vp = OBJECT_TO_JSVAL(url->url_object);
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(JSBool)
- loc_reload(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- if (!JS_InstanceOf(cx, obj, &lm_location_class, argv))
- return JS_FALSE;
- return url_load(cx, obj, get_url_string(cx, obj),
- (JSVAL_IS_BOOLEAN(argv[0]) && JSVAL_TO_BOOLEAN(argv[0]))
- ? NET_SUPER_RELOAD
- : NET_NORMAL_RELOAD);
- }
-
- PR_STATIC_CALLBACK(JSBool)
- loc_replace(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- JSURL *url;
- JSBool ans;
-
- if (!(url = JS_GetInstancePrivate(cx, obj, &lm_location_class, argv)))
- return JS_FALSE;
- url->url_decoder->replace_location = JS_TRUE;
- /* Note: loc_assign ignores the id in favor of its own id anyway */
- ans = loc_assign(cx, obj, 0, argv);
- *rval = *argv;
- return ans;
- }
-
- static JSFunctionSpec loc_methods[] = {
- {lm_toString_str, loc_toString, 0},
- {lm_reload_str, loc_reload, 1},
- {lm_replace_str, loc_replace, 1},
- {0}
- };
-
- JSObject *
- lm_DefineLocation(MochaDecoder *decoder)
- {
- JSObject *obj;
- JSContext *cx;
- JSURL *url;
-
- obj = decoder->location;
- if (obj)
- return obj;
-
- cx = decoder->js_context;
- url = JS_malloc(cx, sizeof *url);
- if (!url)
- return NULL;
- XP_BZERO(url, sizeof *url);
-
- obj = JS_InitClass(cx, decoder->window_object, NULL, &lm_location_class,
- Location, 0, url_props, loc_methods, NULL, NULL);
- if (!obj || !JS_SetPrivate(cx, obj, url)) {
- JS_free(cx, url);
- return NULL;
- }
-
- /* XXX common subroutine this and above with lm_NewURL */
- if (!JS_AddNamedRoot(cx, &url->href, "loc.text"))
- return NULL;
- if (!JS_AddNamedRoot(cx, &url->target, "loc.target"))
- return NULL;
- if (!JS_AddNamedRoot(cx, &url->text, "loc.text"))
- return NULL;
-
- if (!JS_DefineProperty(cx, decoder->window_object, lm_location_str,
- OBJECT_TO_JSVAL(obj), NULL, loc_assign,
- JSPROP_ENUMERATE | JSPROP_PERMANENT)) {
- return NULL;
- }
- if (!JS_DefineProperty(cx, decoder->document, lm_location_str,
- OBJECT_TO_JSVAL(obj), NULL, loc_assign,
- JSPROP_ENUMERATE | JSPROP_PERMANENT)) {
- return NULL;
- }
-
- /* Define the Location object (the current URL). */
- url->url_decoder = HOLD_BACK_COUNT(decoder);
- url->url_type = FORM_TYPE_NONE;
- url->url_object = obj;
- url->index = URL_NOT_INDEXED;
- decoder->location = obj;
- return obj;
- }
-