From 68c33afaa7145a244adde64fbca45dce62635c7a Mon Sep 17 00:00:00 2001
From: Andrew Hodgkinson <ahodgkin@gitlab.riscosopen.org>
Date: Wed, 30 Jul 1997 12:39:15 +0000
Subject: [PATCH] In the middle of customer support work.

---
 Resources/UK/Browse/!Run,feb   |   5 +-
 Resources/UK/Browse/!RunD,feb  |   7 +-
 Resources/UK/Browse/Choices    |   2 +-
 Resources/UK/Browse/Messages   |  13 ++-
 Resources/UK/Phoenix/!RunD,feb |   4 +-
 Resources/UK/Phoenix/Messages  |   4 +-
 Resources/UK/Ursula/!Run,feb   |   2 +-
 Resources/UK/Ursula/!RunD,feb  |   4 +-
 Resources/UK/Ursula/Messages   |   2 +-
 c/Cookies                      |  94 +++++++++++++++++++
 c/Fetch                        |  42 ++++++---
 c/Forms                        |   2 +-
 c/Frames                       |  26 +++---
 c/Global                       |   1 +
 c/Handlers                     |   9 +-
 c/JavaScript                   | 162 ++++++++++++++++++++++++++++++++-
 c/Main                         |   5 +
 c/TokenUtils                   |   3 +
 c/Utils                        | 129 +++++++++++++++++++++++++-
 c/meta                         |  12 +--
 h/Cookies                      |  22 +++++
 h/JavaScript                   |   5 +-
 h/MiscDefs                     |   7 ++
 h/Utils                        |   2 +
 24 files changed, 503 insertions(+), 61 deletions(-)
 create mode 100644 c/Cookies
 create mode 100644 h/Cookies

diff --git a/Resources/UK/Browse/!Run,feb b/Resources/UK/Browse/!Run,feb
index 6cfdfad..1f58000 100644
--- a/Resources/UK/Browse/!Run,feb
+++ b/Resources/UK/Browse/!Run,feb
@@ -3,7 +3,8 @@ Set Browse$Path <Browse$Dir>.
 
 | HTTP fetcher controls
 
-Set   Browse$FakeNetscape on
+Set   Browse$FakeNetscape     off
+Set   Browes$AcceptAllCookies off
 UnSet Browse$CookiePath
 
 | Ensure specific versions of Toolbox modules (or later ones)
@@ -82,4 +83,4 @@ Set Alias$@RunType_F91 /<Browse$Dir>.!Run -uri %%*0
 
 WimpSlot -Min 420K -Max 420K
 
-Run <Browse$Dir>.!RunImage %*0
\ No newline at end of file
+Run <Browse$Dir>.!RunImage %*0
diff --git a/Resources/UK/Browse/!RunD,feb b/Resources/UK/Browse/!RunD,feb
index dd245cb..4d11057 100644
--- a/Resources/UK/Browse/!RunD,feb
+++ b/Resources/UK/Browse/!RunD,feb
@@ -3,7 +3,8 @@ Set Browse$Path <Browse$Dir>.
 
 | HTTP fetcher controls
 
-Set   Browse$FakeNetscape on
+Set   Browse$FakeNetscape     off
+Set   Browse$AcceptAllCookies off
 UnSet Browse$CookiePath
 
 | Ensure specific versions of Toolbox modules (or later ones)
@@ -80,8 +81,8 @@ Set Alias$@RunType_F91 /<Browse$Dir>.!Run -uri %%*0
 
 | And finally, run the application.
 
-WimpSlot -Min 1600K -Max 1600K
+WimpSlot -Min 2000K -Max 2000K
 
 %UnSet ChangeFSI$Dir
 |Run <Browse$Dir>.!RunImage -debug CMal,CFle %*0 2> Pipe:$.StdErr
-Run <Browse$Dir>.!RunImage %*0
\ No newline at end of file
+Run <Browse$Dir>.!RunImage -debug JScr %*0
diff --git a/Resources/UK/Browse/Choices b/Resources/UK/Browse/Choices
index 61d7005..5b04763 100644
--- a/Resources/UK/Browse/Choices
+++ b/Resources/UK/Browse/Choices
@@ -238,7 +238,7 @@ ShowURLs:no
 SaveHistory:yes
 SaveHotlist:yes
 
-RefoWait:no
+RefoWait:yes
 RefoHang:no
 RefoTime:500
 BrickWall:no
diff --git a/Resources/UK/Browse/Messages b/Resources/UK/Browse/Messages
index 3d94a90..4feddc2 100644
--- a/Resources/UK/Browse/Messages
+++ b/Resources/UK/Browse/Messages
@@ -1,6 +1,6 @@
 _TaskName:Browse
 _SpriName:!browse
-Version:1.17 (23-Jul-97)
+Version:1.18 (31-Jul-97)
 
 # Errors, ranked roughly in order of increasing severity
 
@@ -317,6 +317,17 @@ BackOffAt:128
 
 ClientPull:yes
 
+# Debugging support - for testing, report inline JavaScript? Report
+# unknown function calls? Report illegal parameters to hard coded
+# function calls?
+#
+# This section of the Messages file should only be present in Customer
+# builds (don't merge it to others).
+
+DBS_ReportInline:yes
+DBS_ReportUnknown:yes
+DBS_ReportIllegal:yes
+
 # Dynamically created pages. Note that MessageTrans will deal with '%'s,
 # so you need two if you want one.
 
diff --git a/Resources/UK/Phoenix/!RunD,feb b/Resources/UK/Phoenix/!RunD,feb
index 85268d0..9d401bc 100644
--- a/Resources/UK/Phoenix/!RunD,feb
+++ b/Resources/UK/Phoenix/!RunD,feb
@@ -58,8 +58,8 @@ Set Alias$@RunType_F91 /<Browse$Dir>.!Run -uri %%*0
 
 | And finally, run the application.
 
-WimpSlot -Min 1600K -Max 1600K
+WimpSlot -Min 2000K -Max 2000K
 
 %UnSet ChangeFSI$Dir
 |Run <Browse$Dir>.!RunImage -debug CMal,CFle %*0 2> Pipe:$.StdErr
-Run <Browse$Dir>.!RunImage %*0
\ No newline at end of file
+Run <Browse$Dir>.!RunImage %*0
diff --git a/Resources/UK/Phoenix/Messages b/Resources/UK/Phoenix/Messages
index e941935..5c3dca4 100644
--- a/Resources/UK/Phoenix/Messages
+++ b/Resources/UK/Phoenix/Messages
@@ -1,6 +1,6 @@
-_TaskName:Browse
+_TaskName:Phoenix
 _SpriName:!browse
-Version:1.17 (23-Jul-97)
+Version:1.18 (31-Jul-97)
 
 # Errors, ranked roughly in order of increasing severity
 
diff --git a/Resources/UK/Ursula/!Run,feb b/Resources/UK/Ursula/!Run,feb
index cee8363..ed69e12 100644
--- a/Resources/UK/Ursula/!Run,feb
+++ b/Resources/UK/Ursula/!Run,feb
@@ -77,4 +77,4 @@ Set Alias$@RunType_F91 /<Browse$Dir>.!Run -uri %%*0
 
 WimpSlot -Min 420K -Max 420K
 
-Run <Browse$Dir>.!RunImage %*0
\ No newline at end of file
+Run <Browse$Dir>.!RunImage %*0
diff --git a/Resources/UK/Ursula/!RunD,feb b/Resources/UK/Ursula/!RunD,feb
index c0a72aa..31db6ba 100644
--- a/Resources/UK/Ursula/!RunD,feb
+++ b/Resources/UK/Ursula/!RunD,feb
@@ -75,8 +75,8 @@ Set Alias$@RunType_F91 /<Browse$Dir>.!Run -uri %%*0
 
 | And finally, run the application.
 
-WimpSlot -Min 1600K -Max 1600K
+WimpSlot -Min 2000K -Max 2000K
 
 %UnSet ChangeFSI$Dir
 |Run <Browse$Dir>.!RunImage -debug CMal,CFle %*0 2> Pipe:$.StdErr
-Run <Browse$Dir>.!RunImage %*0
\ No newline at end of file
+Run <Browse$Dir>.!RunImage %*0
diff --git a/Resources/UK/Ursula/Messages b/Resources/UK/Ursula/Messages
index 2478e58..ff8eb78 100644
--- a/Resources/UK/Ursula/Messages
+++ b/Resources/UK/Ursula/Messages
@@ -1,6 +1,6 @@
 _TaskName:Browse
 _SpriName:!browse
-Version:1.17 (23-Jul-97)
+Version:1.18 (31-Jul-97)
 
 # Errors, ranked roughly in order of increasing severity
 
diff --git a/c/Cookies b/c/Cookies
new file mode 100644
index 0000000..a713ebd
--- /dev/null
+++ b/c/Cookies
@@ -0,0 +1,94 @@
+/* Copyright 1997 Acorn Computers Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*************************************************/
+/* File   : Cookies.c                            */
+/* Purpose: Browser-end HTTP Cookie support.     */
+/* Author : A.D.Hodgkinson                       */
+/* History: 28-Jul-96: Created                   */
+/*************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "swis.h"
+
+#include "HTMLLib.h" /* HTML library API, Which will include html2_ext.h, tags.h and struct.h */
+
+#include "wimp.h"
+#include "wimplib.h"
+#include "event.h"
+
+#include "svcprint.h"
+#include "Global.h"
+#include "Utils.h"
+
+#include "MiscDefs.h"
+
+#include "Cookies.h"
+
+/*************************************************/
+/* cookies_process_cookie()                      */
+/*                                               */
+/* If a call to URL_ReadData flags (through bit  */
+/* 16 of the returned status word being set)     */
+/* that a cookie / some cookies have arrived,    */
+/* this function deals with sending that cookie  */
+/* on or getting rid of it. This may or may not  */
+/* involve user level interaction.               */
+/*                                               */
+/* Parameters: Pointer to a browser_data struct  */
+/*             relevant to the fetch.            */
+/*************************************************/
+
+_kernel_oserror * cookies_process_cookie(browser_data * b)
+{
+  _kernel_oserror * e;
+  int               handle = 0;
+  int               flags;
+  int               ncookies;
+  int               unread = 1;
+  char            * domain;
+  char            * name;
+  char            * value;
+  char            * path;
+
+  while (unread)
+  {
+    e = _swix(HTTP_EnumerateCookies,
+              _INR(0,1) | _OUTR(0,7),
+
+              0,
+              handle,
+
+              &flags,
+              &handle,
+              &ncookies,
+              &unread,
+              &domain,
+              &name,
+              &value,
+              &path);
+
+    /* Exit conditions */
+
+    if (e) return e;
+    if (!handle) break;
+
+    Printf("cookie name: '%s'\n",name);
+  }
+
+  return NULL;
+}
diff --git a/c/Fetch b/c/Fetch
index 07c49df..26961f0 100644
--- a/c/Fetch
+++ b/c/Fetch
@@ -42,6 +42,7 @@
 
 #include "Authorise.h"
 #include "Browser.h"
+#include "Cookies.h"
 #include "FontManage.h"
 #include "Forms.h"
 #include "Frames.h"
@@ -2169,13 +2170,15 @@ _kernel_oserror * html_get_next_token(browser_data * b, unsigned int handle, int
     return &erb;
   }
 
-  /* Only look for an anchor and use url_read_data() for URLs which */
+  /* Only look for an anchor and use url_read_data for URLs which */
   /* are not internal.                                              */
 
   StrNCpy0(ref_url, url);
 
   if (image || b->displayed == Display_Fetched_Page)
   {
+    int status = 0;
+
     /* Want to make sure we work on a URL which doesn't */
     /* have an anchor in it, so copy over the url to    */
     /* a local buffer and if there's a '#' marking an   */
@@ -2191,13 +2194,21 @@ _kernel_oserror * html_get_next_token(browser_data * b, unsigned int handle, int
     /* module. The url_read_data call puts the number of bytes read  */
     /* into r.                                                       */
 
-    if (!authorising && up->fetching && (up->authorised != 1)) e = url_read_data(0,               /* Flags - must be 0 at present */
-                                                                                 handle,          /* Session handle               */
-                                                                                 fetch_buffer,    /* Buffer to receive data       */
-                                                                                 FetchBufferSize, /* The buffer's size            */
-                                                                                 NULL,            /* (Would be protocol status)   */
-                                                                                 &r,              /* Number of bytes read         */
-                                                                                 remaining);      /* Number of bytes left to get  */
+    if (!authorising && up->fetching && (up->authorised != 1))
+    {
+      e = url_read_data(0,               /* Flags - must be 0 at present */
+                        handle,          /* Session handle               */
+                        fetch_buffer,    /* Buffer to receive data       */
+                        FetchBufferSize, /* The buffer's size            */
+
+                        &status,         /* Protocol status              */
+                        &r,              /* Number of bytes read         */
+                        remaining);      /* Number of bytes left to get  */
+
+      /* Deal with cookies */
+
+      if (!e && (status & (1u<<16))) e = cookies_process_cookie(b);
+    }
   }
   else
   {
@@ -2910,20 +2921,20 @@ _kernel_oserror * html_get_next_token(browser_data * b, unsigned int handle, int
     /* if it was not)                                                */
     }
 
-  /* Closure of 'if' statement that followed the url_read_data()  */
+  /* Closure of 'if' statement that followed the url_read_data    */
   /* function call and associated memory allocation procedures,   */
   /* and only proceeded if data had been fetched and authoristion */
   /* was not flagged as being in progress.                        */
   }
 
-  /* If no data has been fetched from the url_read_data() call */
+  /* If no data has been fetched from the url_read_data call   */
   /* from earlier on, and there hasn't been an error flagged   */
   /* so far, and both the general 'authorisation taking place' */
   /* and urlstat-based 'authorisation in progress' flags are   */
   /* clear, ask the URL module for its current status. If it   */
   /* says it has finished (which would explain this set of     */
   /* circumstances - basically, having no data from the        */
-  /* url_read_data() call but nothing else is wrong), set the  */
+  /* url_read_data call but nothing else is wrong), set the    */
   /* urlstat structure flag to say fetching is no longer in    */
   /* progress.                                                 */
 
@@ -3272,6 +3283,7 @@ _kernel_oserror * url_get_url(unsigned int flags, unsigned int handle, int metho
 _kernel_oserror * url_read_data(unsigned int flags, unsigned int handle, void * buffer,
                                 int size, int * status, int * read, int * pending)
 {
+
   _kernel_oserror * e;
   int               s, r, p = 0;
 
@@ -3281,8 +3293,8 @@ _kernel_oserror * url_read_data(unsigned int flags, unsigned int handle, void *
 
   /* Ensure all returned data is set to a sensible default to start with */
 
-  if (status) * status = 0;
-  if (read) * read = 0;
+  if (status)  * status  = 0;
+  if (read)    * read    = 0;
   if (pending) * pending = 0;
 
   /* Call the URL module */
@@ -3299,6 +3311,10 @@ _kernel_oserror * url_read_data(unsigned int flags, unsigned int handle, void *
             &r,
             &p);
 
+  #ifdef TRACE
+    if (tl & (1u<<6)) Printf("url_read_data: Status %p, error %p returned\n",s,e);
+  #endif
+
   /* In the absence of any errors, fill in the relevant returned data */
 
   if (!e)
diff --git a/c/Forms b/c/Forms
index 642548f..8448112 100644
--- a/c/Forms
+++ b/c/Forms
@@ -2865,7 +2865,7 @@ static _kernel_oserror * form_build_data(browser_data * b, HStream * token, int
 
   tp = hp->token;
 
-  if (HtmlFORMmethod(tp)==formmethod_GET && HtmlFORMaction(tp))
+  if (HtmlFORMmethod(tp) == formmethod_GET && HtmlFORMaction(tp))
   {
     /* A GET form  - put the URL in */
 
diff --git a/c/Frames b/c/Frames
index 958cc27..71d6c98 100644
--- a/c/Frames
+++ b/c/Frames
@@ -27,8 +27,6 @@
 #include "swis.h"
 #include "flex.h"
 
-#include "unixlib.h" /* For case insensitive strcmps only */
-
 #include "HTMLLib.h" /* HTML library API, Which will include html2_ext.h, tags.h and struct.h */
 
 #include "wimp.h"
@@ -1495,13 +1493,11 @@ browser_data * frames_find_named(browser_data * parent, char * name)
 {
   int child = 0;
 
-  /* Can't proceed with this browser window if it hasn't got a name */
-
   if (!parent || !name || (name && !*name)) return NULL;
 
   /* If the parent matches the given name, return it */
 
-  if (parent->window_name && *parent->window_name && !strcasecmp(parent->window_name, name)) return parent;
+  if (parent->window_name && *parent->window_name && !utils_strcasecmp(parent->window_name, name)) return parent;
 
   /* Otherwise, go through the list of children */
 
@@ -1528,6 +1524,12 @@ browser_data * frames_find_named(browser_data * parent, char * name)
 /* lies in, the browser to which the target      */
 /* refers.                                       */
 /*                                               */
+/* If you want to pass in a specific target      */
+/* string, just throw an HStream on the stack    */
+/* and make the 'target' field point to the      */
+/* string - the function doesn't look at any     */
+/* other field in the HStream.                   */
+/*                                               */
 /* Parameters: Pointer to a browser_data struct  */
 /*             that the tag lies in;             */
 /*                                               */
@@ -1568,7 +1570,7 @@ browser_data * frames_find_target(browser_data * b, HStream * t)
       if (tl & (1u<<17)) Printf("frames_find_target: Target='%s'\n",t->target);
     #endif
 
-    if (!strcasecmp(t->target, "_top")) /* Open in the top level window */
+    if (!utils_strcasecmp(t->target, "_top")) /* Open in the top level window */
     {
       ancestor = b->ancestor;
       if (!ancestor) ancestor = b->real_parent;
@@ -1576,15 +1578,15 @@ browser_data * frames_find_target(browser_data * b, HStream * t)
 
       return ancestor;
     }
-    else if (!strcasecmp(t->target, "_self")) /* Open within the frame */
+    else if (!utils_strcasecmp(t->target, "_self")) /* Open within the frame */
     {
       return b;
     }
-    else if (!strcasecmp(t->target, "_blank")) /* Open in a new, blank window */
+    else if (!utils_strcasecmp(t->target, "_blank")) /* Open in a new, blank window */
     {
       return NULL;
     }
-    else if (!strcasecmp(t->target, "_parent")) /* Open in the frame's parent */
+    else if (!utils_strcasecmp(t->target, "_parent")) /* Open in the frame's parent */
     {
       browser_data * parent = b->real_parent;
 
@@ -1631,9 +1633,9 @@ browser_data * frames_find_target(browser_data * b, HStream * t)
           while (named && !found)
           {
             if (
-                 named->window_name                         &&
-                 *named->window_name                        &&
-                 !strcasecmp(named->window_name, t->target)
+                 named->window_name                               &&
+                 *named->window_name                              &&
+                 !utils_strcasecmp(named->window_name, t->target)
                )
                found = named;
 
diff --git a/c/Global b/c/Global
index 8486aa3..186dbb2 100644
--- a/c/Global
+++ b/c/Global
@@ -82,6 +82,7 @@
   /* 21   URI handler interfacing          URIH   2097152 */
   /* 22   Keyboard control functions       KeyC   4194304 */
   /* 23   Redraw rectangle display         RBox   8388608 */
+  /* 24   JavaScript functinos             JScr  16777216 */
   /*                                                      */
   /* To use, put -debug or -d into the command line args  */
   /* for running !RunImage, followed by a series of comma */
diff --git a/c/Handlers b/c/Handlers
index 9579bb0..4ea3e23 100644
--- a/c/Handlers
+++ b/c/Handlers
@@ -29,8 +29,6 @@
 #include "kernel.h"
 #include "flex.h"
 
-#include "unixlib.h" /* For case insensitive strcmps only */
-
 #include "HTMLLib.h" /* HTML library API, Which will include html2_ext.h, tags.h and struct.h */
 #include "URI.h"     /* URI handler API, in URILib:h */
 
@@ -59,6 +57,7 @@
 #include "Frames.h"
 #include "History.h"
 #include "Images.h"
+#include "JavaScript.h"
 #include "MiscDefs.h"
 #include "Mouse.h"
 #include "Printing.h"
@@ -1629,6 +1628,10 @@ int handle_link_clicks(int eventcode, WimpPollBlock * b, IdBlock * idb, browser_
       {
         if (p->anchor)
         {
+          /* First, do we have JavaScript code to deal with? */
+
+          if (p->onclick && *p->onclick) ChkError(javascript_href_onclick(handle, p));
+
           /* Image maps */
 
           if ((p->style & IMG) && (p->type & TYPE_ISMAP))
@@ -1775,6 +1778,8 @@ int handle_link_clicks(int eventcode, WimpPollBlock * b, IdBlock * idb, browser_
         /* a link, then again, follow that link.                   */
         /*                                                         */
         /* This behaviour is due to change (save link contents).   */
+        /* Note that JavaScript onClick events are not activated   */
+        /* if you shift+click (this is deliberate!).               */
 
         if (p->anchor && !(p->style & IMG))
         {
diff --git a/c/JavaScript b/c/JavaScript
index 04d51d8..e0dced6 100644
--- a/c/JavaScript
+++ b/c/JavaScript
@@ -24,7 +24,6 @@
 #include <string.h>
 
 #include "swis.h"
-#include "flex.h"
 
 #include "HTMLLib.h" /* HTML library API, Which will include html2_ext.h, tags.h and struct.h */
 
@@ -36,6 +35,9 @@
 #include "Global.h"
 #include "Utils.h"
 
+#include "Browser.h"
+#include "FetchPage.h"
+#include "Frames.h"
 #include "Customer.h"
 
 #include "JavaScript.h"
@@ -56,14 +58,164 @@
 
 _kernel_oserror * javascript_body_onload(browser_data * b)
 {
+  _kernel_oserror * e = NULL;
+
+  #ifdef TRACE
+    if (tl & (1u<<24)) Printf("javascript_body_onload: Called\n");
+  #endif
+
   #ifdef CUSTOMER_SPECIAL
 
-    return customer_body_onload(b);
+    /* Only call customer_ functions if on the customer's site */
+
+    if (strstr(browser_current_url(b), "www.customer.com"))
+    {
+      e = customer_body_onload(b);
+    }
 
   #endif
 
-  // Don't forget to set the onload field to NULL after use,
-  // or this'll keep getting called as images fetch!
+  b->onload = NULL;
+
+  return e;
+}
+
+/*************************************************/
+/* javascript_href_onclick()                     */
+/*                                               */
+/* When something is clicked upon that has an    */
+/* onClick attribute specified for it, this      */
+/* function is called with the details of that   */
+/* attribute.                                    */
+/*                                               */
+/* Parameters: Pointer to a browser_data struct  */
+/*             relevant to the item clicked on;  */
+/*                                               */
+/*             Pointer to the token representing */
+/*             that item.                        */
+/*************************************************/
+
+_kernel_oserror * javascript_href_onclick(browser_data * b, HStream * t)
+{
+  _kernel_oserror * e = NULL;
+
+  #ifdef TRACE
+    if (tl & (1u<<24)) Printf("javascript_href_onclick: Called\n");
+  #endif
+
+  #ifdef CUSTOMER_SPECIAL
+
+    /* Only call customer_ functions if on the customer's site */
+
+    if (strstr(browser_current_url(b), "www.customer.com"))
+    {
+      e = customer_href_onclick(b, t);
+    }
+
+  #endif
+
+  return e;
+}
+
+/*************************************************/
+/* javascript_window_open()                      */
+/*                                               */
+/* Opens a given URL in a given target window.   */
+/*                                               */
+/* Parameters: Pointer to a browser_data struct  */
+/*             relevant to the window_open call; */
+/*                                               */
+/*             1 if the specified target window  */
+/*             must be found to proceed, else 0  */
+/*             (if the target isn't found the    */
+/*             URL is opened in the given        */
+/*             browser instead);                 */
+/*                                               */
+/*             1 if the URL displayed in the     */
+/*             target is to be recorded in the   */
+/*             History before the new one is     */
+/*             fetched, else 0;                  */
+/*                                               */
+/*             Pointer to the URL to fetch;      */
+/*                                               */
+/*             Pointer to the target (or NULL /  */
+/*             a null string for the given       */
+/*             browser).                         */
+/*************************************************/
+
+_kernel_oserror * javascript_window_open(browser_data * b, int must_find, int record, char * url, char * target)
+{
+  browser_data * targetted = b;
+
+  #ifdef TRACE
+    if (tl & (1u<<24)) Printf("javascript_window_open: Called for %p with '%s' and target '%s'\n",b,url,target);
+  #endif
+
+  /* Exit if no URL or base browser is given */
+
+  if (!b || !url || !*url) return NULL;
+
+  /* If a target is specified, try and find it */
+
+  if (target && *target)
+  {
+    browser_data * ancestor = b->ancestor;
+
+    if (!ancestor) ancestor = b;
+
+    #ifdef TRACE
+      if (tl & (1u<<24)) Printf("javascript_window_open: Proceeding with target '%s'\n",target);
+    #endif
+
+    targetted = frames_find_named(ancestor, target);
+
+    #ifdef TRACE
+      if (tl & (1u<<24)) Printf("javascript_window_open: targetted = %p\n",targetted);
+    #endif
+
+    /* If the target can't be found and the parameters specify it must be, */
+    /* then exit; else target the base browser instead.                    */
+
+    if (!targetted)
+    {
+      if (must_find) return NULL;
+      else targetted = b;
+    }
+  }
+
+  /* Open the URL */
+
+  #ifdef TRACE
+    if (tl & (1u<<24)) Printf("javascript_window_open: Opening to target %p\n",targetted);
+  #endif
+
+  /* Relativise the URL if necessary */
+
+  if (!strstr(url, "http://"))
+  {
+    browser_data * ancestor = targetted->ancestor;
+    char         * r_url;
+
+    if (!ancestor) ancestor = targetted;
+
+    #ifdef TRACE
+      if (tl & (1u<<24)) Printf("javascript_window_open: Relativising URL\n");
+    #endif
+
+    /* Need to go down a sequence of options for which URL to relativise to! */
+
+    r_url = browser_current_url(targetted);
+
+    if (!r_url) r_url = browser_fetch_url(targetted);
+    if (!r_url) r_url = browser_current_url(ancestor);
+    if (!r_url) r_url = browser_fetch_url(ancestor);
+
+    url = HtmlRelativiseURL(r_url, url, targetted->stream);
+
+    #ifdef TRACE
+      if (tl & (1u<<24)) Printf("javascript_window_open: Relativised URL is '%s'\n",url);
+    #endif
+  }
 
-  return NULL;
+  return fetchpage_new(targetted, url, record);
 }
diff --git a/c/Main b/c/Main
index 1017e8d..17bacc4 100644
--- a/c/Main
+++ b/c/Main
@@ -480,6 +480,10 @@ static void initialise_app(void)
     else if (version >= 5)        uri_module_present = 1;
   }
 
+  /* Try and set the user agent string for HTTP fetches. */
+
+  show_error(utils_set_http_agent());
+
   /* Find out window tool sizes */
 
   ChkError(windows_initialise_tool_sizes());
@@ -972,6 +976,7 @@ int main(int argc, char * argv[])
         if (strstr(argv[argp + 1], "URIH")) tl |= (1u<<21);
         if (strstr(argv[argp + 1], "KeyC")) tl |= (1u<<22);
         if (strstr(argv[argp + 1], "RBox")) tl |= (1u<<23);
+        if (strstr(argv[argp + 1], "JScr")) tl |= (1u<<24);
 
         if (strstr(argv[argp + 1], "All"))  tl  = 0xffffffff;
 
diff --git a/c/TokenUtils b/c/TokenUtils
index 33e8626..77102a8 100644
--- a/c/TokenUtils
+++ b/c/TokenUtils
@@ -92,6 +92,9 @@ void tokenutils_anchor_range(browser_data * b, HStream * token, HStream ** first
   HStream * end   = NULL;
   HStream * store = NULL;
 
+  if (first) *first = NULL;
+  if (last)  *last  = NULL;
+
   /* Can only proceed if the given token represents a link */
 
   if (token && (token->style & A) && token->anchor)
diff --git a/c/Utils b/c/Utils
index ae475ed..0571e88 100644
--- a/c/Utils
+++ b/c/Utils
@@ -66,7 +66,11 @@
 
 #include "Utils.h"
 
-/* Constant definitions */
+/* Local definitions */
+
+#define AGENT_START  "Mozilla/2.0 (compatible; Acorn "
+#define AGENT_MIDDLE "; RISC OS "
+#define AGENT_END    ")"
 
 #define MillipointsPerOSUnit 400
 
@@ -2087,15 +2091,38 @@ int encode_base64(const char * in, int len, char * out)
   return out - out_ptr;
 }
 
+/*************************************************/
+/* utils_strcasecmp()                            */
+/*                                               */
+/* Case insensitive comparison of two given      */
+/* strings.                                      */
+/*                                               */
+/* Parameters: As strcmp.                        */
+/*                                               */
+/* Returns:    As strcmp.                        */
+/*************************************************/
+
+int utils_strcasecmp(const char * a, const char * b)
+{
+  while(*a && *b)
+  {
+    if (tolower(*a++) != tolower(*b++)) return 1;
+  }
+
+  if (!*a && !*b) return 0;
+
+  return 1;
+}
+
 /*************************************************/
 /* utils_strncasecmp()                           */
 /*                                               */
-/* Case insensitive comparisson of n chars of    */
-/* two given strings.                            */
+/* Case insensitive comparison of n chars of two */
+/* given strings.                                */
 /*                                               */
-/* Parameters: As strncmp                        */
+/* Parameters: As strncmp.                       */
 /*                                               */
-/* Returns:    As strncmp                        */
+/* Returns:    As strncmp.                       */
 /*************************************************/
 
 int utils_strncasecmp(const char * a, const char * b, unsigned int n)
@@ -2201,3 +2228,95 @@ _kernel_oserror * utils_stop_webserv(void)
 }
 
 /*************************************************/
+/* utils_set_http_agent()                        */
+/*                                               */
+/* Works out an appropriate HTTP agent string    */
+/* and attempts to tell the HTTP module to use   */
+/* this in headers for fetches.                  */
+/*                                               */
+/* If HTTP is not present, the routine will fail */
+/* silently.                                     */
+/*************************************************/
+
+_kernel_oserror * utils_set_http_agent(void)
+{
+  _kernel_oserror * e;
+  char              agent[1024];
+  char              ver  [32];
+  int               modnum, bcdver = 0;
+
+  /* The AGENT_... definitions are at the top of ths file.     */
+  /*                                                           */
+  /* First, the string start, e.g. 'Mozilla/2.0 (compatible; ' */
+
+  StrNCpy0(agent, AGENT_START);
+
+  /* The browser name */
+
+  *lasttokn = 0; /* Being very (maybe over?) cautions here */
+  *tokens   = 0;
+  lookup_token("_TaskName",1,0);
+  if (strlen(tokens) + strlen(agent) + 2 < sizeof(agent))
+  {
+    strcat(agent, tokens);
+    strcat(agent, " ");
+  }
+
+  /* The browser version */
+
+  *lasttokn = 0;
+  *tokens   = 0;
+  lookup_token("Version",1,0);
+  if (strlen(tokens) + strlen(agent) + 1 < sizeof(agent)) strcat(agent, tokens);
+
+  /* Intermediate string */
+
+  if (strlen(agent) + strlen(AGENT_MIDDLE) + 1 < sizeof(agent)) strcat(agent, AGENT_MIDDLE);
+
+  /* Extract the Utility Module version number */
+
+  e = _swix(OS_Module,
+            _INR(0,1) | _OUT(1),
+
+            18,
+            "UtilityModule",
+
+            &modnum);
+
+  if (e) return e;
+
+  e = _swix(OS_Module,
+            _INR(0,2) | _OUT(6),
+
+            20,
+            modnum,
+            -1,
+
+            &bcdver);
+
+  if (e) return e;
+
+  /* Write the version number and put it into the agent string */
+
+  sprintf(ver, "%d.%02x", bcdver >> 16, (bcdver & 0xffff) >> 8);
+
+  if (strlen(agent) + strlen(ver) + 1 < sizeof(agent)) strcat(agent, ver);
+
+  /* Finish things off */
+
+  if (strlen(agent) + strlen(AGENT_END) + 1 < sizeof(agent)) strcat(agent, AGENT_END);
+
+  /* Set the agent string, ignoring errors (as, say, the HTTP */
+  /* module may not be present at all)                        */
+
+  _swix(HTTP_UserAgent,
+        _IN(0),
+
+        agent);
+
+  /* Finished. */
+
+  return NULL;
+}
+
+/*************************************************/
diff --git a/c/meta b/c/meta
index d911bf9..2f67de9 100644
--- a/c/meta
+++ b/c/meta
@@ -26,8 +26,6 @@
 #include "swis.h"
 #include "flex.h"
 
-#include "unixlib.h" /* For case insensitive strcmps only */
-
 #include "HTMLLib.h" /* HTML library API, Which will include html2_ext.h, tags.h and struct.h */
 
 #include "wimp.h"
@@ -75,14 +73,14 @@ _kernel_oserror * meta_process_tag(browser_data * b, HStream * t)
 
   /* Extract information from the token */
 
-  name    = HtmlMETAname      (t);
-  equiv   = HtmlMETAhttp_equiv(t);
-  content = HtmlMETAcontent   (t);
-  scheme  = HtmlMETAscheme    (t);
+  name    = HtmlMETAname       (t);
+  equiv   = HtmlMETAhttp_equiv (t);
+  content = HtmlMETAcontent    (t);
+  scheme  = HtmlMETAscheme     (t);
 
   /* Work out what to do */
 
-  if (!strcasecmp(equiv, "refresh"))
+  if (!utils_strcasecmp(equiv, "refresh"))
   {
     /* Refresh - load a new page or reload the current page */
     /* after a certain amount of time                       */
diff --git a/h/Cookies b/h/Cookies
new file mode 100644
index 0000000..1638c05
--- /dev/null
+++ b/h/Cookies
@@ -0,0 +1,22 @@
+/* Copyright 1997 Acorn Computers Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*************************************************/
+/* File   : Cookies.h                            */
+/* Purpose: Browser-end HTTP Cookie support.     */
+/* Author : A.D.Hodgkinson                       */
+/* History: 28-Jul-96: Created                   */
+/*************************************************/
+
+_kernel_oserror * cookies_process_cookie (browser_data * b);
diff --git a/h/JavaScript b/h/JavaScript
index bd8e0ef..ff64b4f 100644
--- a/h/JavaScript
+++ b/h/JavaScript
@@ -19,4 +19,7 @@
 /* History: 24-Jul-97: Created                     */
 /***************************************************/
 
-_kernel_oserror * javascript_body_onload (browser_data * b);
+_kernel_oserror * javascript_body_onload  (browser_data * b);
+_kernel_oserror * javascript_href_onclick (browser_data * b, HStream * t);
+
+_kernel_oserror * javascript_window_open  (browser_data * b, int must_find, int record, char * url, char * target);
diff --git a/h/MiscDefs b/h/MiscDefs
index fb3faf1..6928adf 100644
--- a/h/MiscDefs
+++ b/h/MiscDefs
@@ -37,3 +37,10 @@
 #define TaskModule_DeRegisterService 0x4d303
 
 #define Message_Service              0x4d300
+
+/* HTTP module SWI numbers */
+
+#define HTTP_EnumerateCookies        0x83f85
+#define HTTP_ConsumeCookie           0x83f86
+#define HTTP_AddCookie               0x83f87
+#define HTTP_UserAgent               0x83f88
diff --git a/h/Utils b/h/Utils
index c4a9034..ea4494d 100644
--- a/h/Utils
+++ b/h/Utils
@@ -99,6 +99,8 @@ int               task_from_window                 (int window_handle);
 int               is_known_browser                 (browser_data * b);
 
 int               encode_base64                    (const char * in, int len, char * out);
+int               utils_strcasecmp                 (const char * a, const char * b);
 int               utils_strncasecmp                (const char * a, const char * b, unsigned int n);
 
 _kernel_oserror * utils_stop_webserv               (void);
+_kernel_oserror * utils_set_http_agent             (void);
-- 
GitLab