Gitweb links:

...log 
http://git.netsurf-browser.org/netsurf.git/shortlog/f4de484d0cf88e1b9f5f86c6d6dcde6c186a6095
...commit 
http://git.netsurf-browser.org/netsurf.git/commit/f4de484d0cf88e1b9f5f86c6d6dcde6c186a6095
...tree 
http://git.netsurf-browser.org/netsurf.git/tree/f4de484d0cf88e1b9f5f86c6d6dcde6c186a6095

The branch, jmb/hsts has been updated
  discards  cbe445e19178045c0bdf649f927e6e7cc904c6c5 (commit)
  discards  c42ea9b30d8197f688eec80c974575eb213a35e6 (commit)
  discards  99a29000b937807c7f946d597295c96733ff60f3 (commit)
  discards  7d7bcb526bc8df9f5705e6a37711eef20da84df1 (commit)
  discards  447e2aa4cb0468907f8996d4e02fb34d19c29510 (commit)
  discards  7d1c92069e3a85f1c340c52c050487ec0073d200 (commit)
  discards  475a0cd5d251fe813373b0ffa4ad85033f0b6dc3 (commit)
       via  f4de484d0cf88e1b9f5f86c6d6dcde6c186a6095 (commit)
       via  1d47a40d46f040164e830b06af662979f5eaecf5 (commit)
       via  da269a97365f90120cce103b481afe1888d458b0 (commit)
       via  869eac18ac15a5b7085412217f9ac7528237384c (commit)
       via  91d1f66cdefb68b2f1859037756c78a25760532d (commit)
       via  2de077e1bac163d3dc33c2f232354fb325cd1883 (commit)
       via  badc0d437adff453f046cd8f0eb46c4fa5afe2bf (commit)
       via  9c164e591f7101ccafb6656cc9c8b286e2c76ca1 (commit)
       via  942ef0df03df8ada109c4dd8a8802b16eeb0e8c8 (commit)
       via  de806db28e91e0c216200eef130d4672e29efb01 (commit)
       via  e864997842e157172211ee0dc749590d7547b594 (commit)
       via  c1e30c0c3a077fff59389b5d7f6debfece704889 (commit)
       via  5094a3fd048e06a49bb232ae7eb09821c512c8a0 (commit)
       via  83e8f377ad4fd99bab6da6eca0228762bc4e630e (commit)

This update added new revisions after undoing existing revisions.  That is
to say, the old revision is not a strict subset of the new revision.  This
situation occurs when you --force push a change and generate a repository
containing something like this:

 * -- * -- B -- O -- O -- O (cbe445e19178045c0bdf649f927e6e7cc904c6c5)
            \
             N -- N -- N (f4de484d0cf88e1b9f5f86c6d6dcde6c186a6095)

When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commitdiff 
http://git.netsurf-browser.org/netsurf.git/commit/?id=f4de484d0cf88e1b9f5f86c6d6dcde6c186a6095
commit f4de484d0cf88e1b9f5f86c6d6dcde6c186a6095
Author: John-Mark Bell <[email protected]>
Commit: John-Mark Bell <[email protected]>

    HSTS: make llcache update policy on 3xx responses

diff --git a/content/llcache.c b/content/llcache.c
index 166804c..54f20e0 100644
--- a/content/llcache.c
+++ b/content/llcache.c
@@ -1985,6 +1985,8 @@ static nserror llcache_fetch_redirect(llcache_object 
*object,
        /* And mark it complete */
        object->fetch.state = LLCACHE_FETCH_COMPLETE;
 
+       (void) llcache_hsts_update_policy(object);
+
        /* Forcibly stop redirecting if we've followed too many redirects */
 #define REDIRECT_LIMIT 10
        if (object->fetch.redirect_count > REDIRECT_LIMIT) {


commitdiff 
http://git.netsurf-browser.org/netsurf.git/commit/?id=1d47a40d46f040164e830b06af662979f5eaecf5
commit 1d47a40d46f040164e830b06af662979f5eaecf5
Author: John-Mark Bell <[email protected]>
Commit: John-Mark Bell <[email protected]>

    HSTS: prevent llcache being nice
    
    If the server has defined a HSTS policy, then the user no longer
    gets to click-through a garbage certificate. Additionally, if
    the server has provided a HSTS policy, it should do TLS properly,
    so don't permit client-driven TLS version downgrades in that case,
    either.

diff --git a/content/llcache.c b/content/llcache.c
index ab69e65..166804c 100644
--- a/content/llcache.c
+++ b/content/llcache.c
@@ -109,6 +109,8 @@ typedef struct {
 
        uint32_t retries_remaining;     /**< Number of times to retry on 
timeout */
 
+       bool hsts_in_use;               /**< Whether HSTS applies to this fetch 
*/
+
        bool tried_with_auth;           /**< Whether we've tried with auth */
 
        bool tried_with_tls_downgrade;  /**< Whether we've tried TLS <= 1.0 */
@@ -904,11 +906,12 @@ static nserror llcache_object_refetch(llcache_object 
*object)
  * \param referer        Referring URL, or NULL for none
  * \param post           POST data, or NULL for GET
  * \param redirect_count  Number of redirects followed so far
+ * \param hsts_in_use     Whether HSTS applies to this fetch
  * \return NSERROR_OK on success, appropriate error otherwise
  */
 static nserror llcache_object_fetch(llcache_object *object, uint32_t flags,
                nsurl *referer, const llcache_post_data *post,
-               uint32_t redirect_count)
+               uint32_t redirect_count, bool hsts_in_use)
 {
        nserror error;
        nsurl *referer_clone = NULL;
@@ -930,6 +933,7 @@ static nserror llcache_object_fetch(llcache_object *object, 
uint32_t flags,
        object->fetch.post = post_clone;
        object->fetch.redirect_count = redirect_count;
        object->fetch.retries_remaining = llcache->fetch_attempts;
+       object->fetch.hsts_in_use = hsts_in_use;
 
        return llcache_object_refetch(object);
 }
@@ -1566,6 +1570,7 @@ llcache_object_fetch_persistent(llcache_object *object,
  * \param referer        Referring URL, or NULL if none
  * \param post           POST data, or NULL for a GET request
  * \param redirect_count  Number of redirects followed so far
+ * \param hsts_in_use     Whether HSTS applies to this fetch
  * \param result         Pointer to location to receive retrieved object
  * \return NSERROR_OK on success, appropriate error otherwise
  */
@@ -1575,6 +1580,7 @@ llcache_object_retrieve_from_cache(nsurl *url,
                                   nsurl *referer,
                                   const llcache_post_data *post,
                                   uint32_t redirect_count,
+                                  bool hsts_in_use,
                                   llcache_object **result)
 {
        nserror error;
@@ -1683,7 +1689,7 @@ llcache_object_retrieve_from_cache(nsurl *url,
 
                        /* Attempt to kick-off fetch */
                        error = llcache_object_fetch(obj, flags, referer, post,
-                                                    redirect_count);
+                                                    redirect_count, 
hsts_in_use);
                        if (error != NSERROR_OK) {
                                newest->candidate_count--;
                                llcache_object_destroy(obj);
@@ -1715,7 +1721,8 @@ llcache_object_retrieve_from_cache(nsurl *url,
        }
 
        /* Attempt to kick-off fetch */
-       error = llcache_object_fetch(obj, flags, referer, post, redirect_count);
+       error = llcache_object_fetch(obj, flags, referer, post,
+                       redirect_count, hsts_in_use);
        if (error != NSERROR_OK) {
                llcache_object_destroy(obj);
                return error;
@@ -1737,6 +1744,7 @@ llcache_object_retrieve_from_cache(nsurl *url,
  * \param referer        Referring URL, or NULL if none
  * \param post           POST data, or NULL for a GET request
  * \param redirect_count  Number of redirects followed so far
+ * \param hsts_in_use     Whether HSTS applies to this fetch
  * \param result         Pointer to location to receive retrieved object
  * \return NSERROR_OK on success, appropriate error otherwise
  */
@@ -1746,6 +1754,7 @@ llcache_object_retrieve(nsurl *url,
                        nsurl *referer,
                        const llcache_post_data *post,
                        uint32_t redirect_count,
+                       bool hsts_in_use,
                        llcache_object **result)
 {
        nserror error;
@@ -1800,7 +1809,7 @@ llcache_object_retrieve(nsurl *url,
 
                /* Attempt to kick-off fetch */
                error = llcache_object_fetch(obj, flags, referer, post,
-                               redirect_count);
+                               redirect_count, hsts_in_use);
                if (error != NSERROR_OK) {
                        llcache_object_destroy(obj);
                        nsurl_unref(defragmented_url);
@@ -1811,7 +1820,8 @@ llcache_object_retrieve(nsurl *url,
                llcache_object_add_to_list(obj, &llcache->uncached_objects);
        } else {
                error = llcache_object_retrieve_from_cache(defragmented_url,
-                               flags, referer, post, redirect_count, &obj);
+                               flags, referer, post, redirect_count,
+                               hsts_in_use, &obj);
                if (error != NSERROR_OK) {
                        nsurl_unref(defragmented_url);
                        return error;
@@ -2058,7 +2068,8 @@ static nserror llcache_fetch_redirect(llcache_object 
*object,
        /* Attempt to fetch target URL */
        error = llcache_object_retrieve(hsts_url, object->fetch.flags,
                        object->fetch.referer, post,
-                       object->fetch.redirect_count + 1, &dest);
+                       object->fetch.redirect_count + 1,
+                       hsts_in_use, &dest);
 
        /* No longer require url */
        nsurl_unref(hsts_url);
@@ -2352,7 +2363,8 @@ static nserror llcache_fetch_cert_error(llcache_object 
*object,
        /* Consider the TLS transport tainted */
        object->fetch.tainted_tls = true;
 
-       if (llcache->query_cb != NULL) {
+       /* Only give the user a chance if HSTS isn't in use for this fetch */
+       if (object->fetch.hsts_in_use == false && llcache->query_cb != NULL) {
                llcache_query query;
 
                /* Emit query for TLS */
@@ -2405,7 +2417,10 @@ static nserror llcache_fetch_ssl_error(llcache_object 
*object)
        /* Consider the TLS transport tainted */
        object->fetch.tainted_tls = true;
 
-       if (object->fetch.tried_with_tls_downgrade == true) {
+       /* Make no attempt to downgrade if HSTS is in use
+        * (i.e. assume server does TLS properly) */
+       if (object->fetch.hsts_in_use ||
+                       object->fetch.tried_with_tls_downgrade) {
                /* Have already tried to downgrade, so give up */
                llcache_event event;
 
@@ -3611,7 +3626,8 @@ nserror llcache_handle_retrieve(nsurl *url, uint32_t 
flags,
 
        /* Retrieve a suitable object from the cache,
         * creating a new one if needed. */
-       error = llcache_object_retrieve(hsts_url, flags, referer, post, 0, 
&object);
+       error = llcache_object_retrieve(hsts_url, flags, referer, post, 0,
+                       hsts_in_use, &object);
        if (error != NSERROR_OK) {
                llcache_object_user_destroy(user);
                nsurl_unref(hsts_url);


commitdiff 
http://git.netsurf-browser.org/netsurf.git/commit/?id=da269a97365f90120cce103b481afe1888d458b0
commit da269a97365f90120cce103b481afe1888d458b0
Author: John-Mark Bell <[email protected]>
Commit: John-Mark Bell <[email protected]>

    HSTS: teach llcache to update and enforce policy.

diff --git a/content/llcache.c b/content/llcache.c
index 58803ea..ab69e65 100644
--- a/content/llcache.c
+++ b/content/llcache.c
@@ -114,6 +114,8 @@ typedef struct {
        bool tried_with_tls_downgrade;  /**< Whether we've tried TLS <= 1.0 */
 
        bool outstanding_query;         /**< Waiting for a query response */
+
+       bool tainted_tls;               /**< Whether the TLS transport is 
tainted */
 } llcache_fetch_ctx;
 
 /**
@@ -1857,6 +1859,90 @@ static nserror llcache_object_add_user(llcache_object 
*object,
 }
 
 /**
+ * Transform a request-URI based on HSTS policy
+ *
+ * \param url URL to transform
+ * \param result Pointer to location to receive transformed URL
+ * \param hsts_in_use Pointer to location to receive HSTS in-use flag
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+static nserror llcache_hsts_transform_url(nsurl *url, nsurl **result,
+               bool *hsts_in_use)
+{
+       lwc_string *scheme = NULL;
+       bool match;
+       nserror error = NSERROR_OK;;
+
+       scheme = nsurl_get_component(url, NSURL_SCHEME);
+       if (lwc_string_caseless_isequal(scheme, corestring_lwc_http,
+                       &match) != lwc_error_ok || match == false) {
+               /* Non-HTTP fetch: ignore */
+               if (scheme != NULL) {
+                       lwc_string_unref(scheme);
+               }
+               *result = nsurl_ref(url);
+               *hsts_in_use = false;
+               return NSERROR_OK;
+       }
+       lwc_string_unref(scheme);
+
+       if (urldb_get_hsts_enabled(url)) {
+               /* Only need to force HTTPS. If original port was explicitly
+                * specified as 80, nsurl_create/join will remove it (as
+                * it's redundant) */
+               error = nsurl_replace_scheme(url, corestring_lwc_https,
+                               result);
+               *hsts_in_use = (error == NSERROR_OK);
+       } else {
+               *result = nsurl_ref(url);
+               *hsts_in_use = false;
+       }
+
+       return error;
+}
+
+/**
+ * Update HSTS policy for target domain.
+ *
+ * \param object Newly-fetched cache object
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+static nserror llcache_hsts_update_policy(llcache_object *object)
+{
+       size_t i;
+       lwc_string *scheme = NULL;
+       bool match = false;
+
+       scheme = nsurl_get_component(object->url, NSURL_SCHEME);
+       if (lwc_string_caseless_isequal(scheme, corestring_lwc_https,
+                       &match) != lwc_error_ok || match == false) {
+               /* Non-HTTPS fetch: ignore */
+               if (scheme != NULL) {
+                       lwc_string_unref(scheme);
+               }
+               return NSERROR_OK;
+       }
+       lwc_string_unref(scheme);
+
+       if (object->fetch.tainted_tls) {
+               /* Transport is tainted: ignore */
+               return NSERROR_OK;
+       }
+
+       for (i = 0; i < object->num_headers; i++) {
+               if (strcasecmp("Strict-Transport-Security",
+                               object->headers[i].name) == 0) {
+                       urldb_set_hsts_policy(object->url,
+                                       object->headers[i].value);
+                       /* Only process the first one we find */
+                       break;
+               }
+       }
+
+       return NSERROR_OK;
+}
+
+/**
  * Handle FETCH_REDIRECT event
  *
  * \param object       Object being redirected
@@ -1871,10 +1957,10 @@ static nserror llcache_fetch_redirect(llcache_object 
*object,
        llcache_object *dest;
        llcache_object_user *user, *next;
        const llcache_post_data *post = object->fetch.post;
-       nsurl *url;
+       nsurl *url, *hsts_url;
        lwc_string *scheme;
        lwc_string *object_scheme;
-       bool match;
+       bool match, hsts_in_use;
        /* Extract HTTP response code from the fetch object */
        long http_code = fetch_http_code(object->fetch.fetch);
        llcache_event event;
@@ -1906,15 +1992,23 @@ static nserror llcache_fetch_redirect(llcache_object 
*object,
        if (error != NSERROR_OK)
                return error;
 
+       /* Perform HSTS transform */
+       error = llcache_hsts_transform_url(url, &hsts_url, &hsts_in_use);
+       if (error != NSERROR_OK) {
+               nsurl_unref(url);
+               return error;
+       }
+       nsurl_unref(url);
+
        /* Inform users of redirect */
        event.type = LLCACHE_EVENT_REDIRECT;
        event.data.redirect.from = object->url;
-       event.data.redirect.to = url;
+       event.data.redirect.to = hsts_url;
 
        error = llcache_send_event_to_users(object, &event);
 
        if (error != NSERROR_OK) {
-               nsurl_unref(url);
+               nsurl_unref(hsts_url);
                return error;
        }
 
@@ -1922,7 +2016,7 @@ static nserror llcache_fetch_redirect(llcache_object 
*object,
         * A "validated" scheme is one over which we have some guarantee that
         * the source is trustworthy. */
        object_scheme = nsurl_get_component(object->url, NSURL_SCHEME);
-       scheme = nsurl_get_component(url, NSURL_SCHEME);
+       scheme = nsurl_get_component(hsts_url, NSURL_SCHEME);
 
        /* resource: and about: are allowed to redirect anywhere */
        if ((lwc_string_isequal(object_scheme, corestring_lwc_resource,
@@ -1938,7 +2032,7 @@ static nserror llcache_fetch_redirect(llcache_object 
*object,
                                &match) == lwc_error_ok && match == true)) {
                        lwc_string_unref(object_scheme);
                        lwc_string_unref(scheme);
-                       nsurl_unref(url);
+                       nsurl_unref(hsts_url);
                        return NSERROR_OK;
                }
        }
@@ -1947,8 +2041,8 @@ static nserror llcache_fetch_redirect(llcache_object 
*object,
        lwc_string_unref(object_scheme);
 
        /* Bail out if we've no way of handling this URL */
-       if (fetch_can_fetch(url) == false) {
-               nsurl_unref(url);
+       if (fetch_can_fetch(hsts_url) == false) {
+               nsurl_unref(hsts_url);
                return NSERROR_OK;
        }
 
@@ -1957,17 +2051,17 @@ static nserror llcache_fetch_redirect(llcache_object 
*object,
                post = NULL;
        } else if (http_code != 307 || post != NULL) {
                /** \todo 300, 305, 307 with POST */
-               nsurl_unref(url);
+               nsurl_unref(hsts_url);
                return NSERROR_OK;
        }
 
        /* Attempt to fetch target URL */
-       error = llcache_object_retrieve(url, object->fetch.flags,
+       error = llcache_object_retrieve(hsts_url, object->fetch.flags,
                        object->fetch.referer, post,
                        object->fetch.redirect_count + 1, &dest);
 
        /* No longer require url */
-       nsurl_unref(url);
+       nsurl_unref(hsts_url);
 
        if (error != NSERROR_OK)
                return error;
@@ -2059,6 +2153,8 @@ static nserror llcache_fetch_notmodified(llcache_object 
*object,
        /* Mark it complete */
        object->fetch.state = LLCACHE_FETCH_COMPLETE;
 
+       (void) llcache_hsts_update_policy(object);
+
        /* Old object will be flushed from the cache on the next poll */
 
        return NSERROR_OK;
@@ -2253,6 +2349,9 @@ static nserror llcache_fetch_cert_error(llcache_object 
*object,
        /* Invalidate cache-control data */
        llcache_invalidate_cache_control_data(object);
 
+       /* Consider the TLS transport tainted */
+       object->fetch.tainted_tls = true;
+
        if (llcache->query_cb != NULL) {
                llcache_query query;
 
@@ -2303,6 +2402,9 @@ static nserror llcache_fetch_ssl_error(llcache_object 
*object)
        /* Invalidate cache-control data */
        llcache_invalidate_cache_control_data(object);
 
+       /* Consider the TLS transport tainted */
+       object->fetch.tainted_tls = true;
+
        if (object->fetch.tried_with_tls_downgrade == true) {
                /* Have already tried to downgrade, so give up */
                llcache_event event;
@@ -2684,6 +2786,8 @@ static void llcache_fetch_callback(const fetch_msg *msg, 
void *p)
                /* record when the fetch finished */
                object->cache.fin_time = time(NULL);
 
+               (void) llcache_hsts_update_policy(object);
+
                guit->misc->schedule(5000, llcache_persist, NULL);
        }
                break;
@@ -3483,23 +3587,34 @@ nserror llcache_handle_retrieve(nsurl *url, uint32_t 
flags,
        nserror error;
        llcache_object_user *user;
        llcache_object *object;
+       nsurl *hsts_url;
+       bool hsts_in_use;
+
+       /* Perform HSTS transform */
+       error = llcache_hsts_transform_url(url, &hsts_url, &hsts_in_use);
+       if (error != NSERROR_OK) {
+               return error;
+       }
 
        /* Can we fetch this URL at all? */
-       if (fetch_can_fetch(url) == false) {
+       if (fetch_can_fetch(hsts_url) == false) {
+               nsurl_unref(hsts_url);
                return NSERROR_NO_FETCH_HANDLER;
        }
 
        /* Create a new object user */
        error = llcache_object_user_new(cb, pw, &user);
        if (error != NSERROR_OK) {
+               nsurl_unref(hsts_url);
                return error;
        }
 
        /* Retrieve a suitable object from the cache,
         * creating a new one if needed. */
-       error = llcache_object_retrieve(url, flags, referer, post, 0, &object);
+       error = llcache_object_retrieve(hsts_url, flags, referer, post, 0, 
&object);
        if (error != NSERROR_OK) {
                llcache_object_user_destroy(user);
+               nsurl_unref(hsts_url);
                return error;
        }
 
@@ -3511,6 +3626,8 @@ nserror llcache_handle_retrieve(nsurl *url, uint32_t 
flags,
        /* Users exist which are now not caught up! */
        llcache_users_not_caught_up();
 
+       nsurl_unref(hsts_url);
+
        return NSERROR_OK;
 }
 


commitdiff 
http://git.netsurf-browser.org/netsurf.git/commit/?id=869eac18ac15a5b7085412217f9ac7528237384c
commit 869eac18ac15a5b7085412217f9ac7528237384c
Author: John-Mark Bell <[email protected]>
Commit: John-Mark Bell <[email protected]>

    NSURL: add ability to create replacement scheme

diff --git a/utils/corestringlist.h b/utils/corestringlist.h
index 8d15eeb..90dd796 100644
--- a/utils/corestringlist.h
+++ b/utils/corestringlist.h
@@ -70,6 +70,7 @@ CORESTRING_LWC_STRING(filename);
 CORESTRING_LWC_STRING(font);
 CORESTRING_LWC_STRING(frame);
 CORESTRING_LWC_STRING(frameset);
+CORESTRING_LWC_STRING(ftp);
 CORESTRING_LWC_STRING(h1);
 CORESTRING_LWC_STRING(h2);
 CORESTRING_LWC_STRING(h3);
diff --git a/utils/nsurl.h b/utils/nsurl.h
index f97562b..054baf2 100644
--- a/utils/nsurl.h
+++ b/utils/nsurl.h
@@ -301,6 +301,25 @@ nserror nsurl_replace_query(const nsurl *url, const char 
*query,
 
 
 /**
+ * Create a NetSurf URL object, with scheme replaced
+ *
+ * \param url    NetSurf URL to create new NetSurf URL from
+ * \param scheme  Scheme to use
+ * \param new_url Returns new NetSurf URL with scheme provided
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * If return value != NSERROR_OK, nothing will be returned in new_url.
+ *
+ * It is up to the client to call nsurl_unref when they are finished with
+ * the created object.
+ *
+ * Any scheme component in url is replaced with scheme in new_url.
+ */
+nserror nsurl_replace_scheme(const nsurl *url, lwc_string *scheme,
+               nsurl **new_url);
+
+
+/**
  * Attempt to find a nice filename for a URL.
  *
  * \param url          A NetSurf URL object to create a filename from
diff --git a/utils/nsurl/nsurl.c b/utils/nsurl/nsurl.c
index 3b0af93..8c769cf 100644
--- a/utils/nsurl/nsurl.c
+++ b/utils/nsurl/nsurl.c
@@ -648,6 +648,93 @@ nserror nsurl_replace_query(const nsurl *url, const char 
*query,
 }
 
 
+/* exported interface, documented in nsurl.h */
+nserror nsurl_replace_scheme(const nsurl *url, lwc_string *scheme,
+               nsurl **new_url)
+{
+       int scheme_len;
+       int base_len;
+       char *pos;
+       size_t len;
+       bool match;
+
+       assert(url != NULL);
+       assert(scheme != NULL);
+
+       /* Get the length of the new scheme */
+       scheme_len = lwc_string_length(scheme);
+
+       /* Find the change in length from url to new_url */
+       base_len = url->length;
+       if (url->components.scheme != NULL) {
+               base_len -= lwc_string_length(url->components.scheme);
+       }
+
+       /* Set new_url's length */
+       len = base_len + scheme_len;
+
+       /* Create NetSurf URL object */
+       *new_url = malloc(sizeof(nsurl) + len + 1); /* Add 1 for \0 */
+       if (*new_url == NULL) {
+               return NSERROR_NOMEM;
+       }
+
+       (*new_url)->length = len;
+
+       /* Set string */
+       pos = (*new_url)->string;
+       memcpy(pos, lwc_string_data(scheme), scheme_len);
+       memcpy(pos + scheme_len,
+                       url->string + url->length - base_len, base_len);
+       pos[len] = '\0';
+
+       /* Copy components */
+       (*new_url)->components.scheme = lwc_string_ref(scheme);
+       (*new_url)->components.username =
+                       nsurl__component_copy(url->components.username);
+       (*new_url)->components.password =
+                       nsurl__component_copy(url->components.password);
+       (*new_url)->components.host =
+                       nsurl__component_copy(url->components.host);
+       (*new_url)->components.port =
+                       nsurl__component_copy(url->components.port);
+       (*new_url)->components.path =
+                       nsurl__component_copy(url->components.path);
+       (*new_url)->components.query =
+                       nsurl__component_copy(url->components.query);
+       (*new_url)->components.fragment =
+                       nsurl__component_copy(url->components.fragment);
+
+       /* Compute new scheme type */
+       if (lwc_string_caseless_isequal(scheme, corestring_lwc_http,
+                       &match) == lwc_error_ok && match == true) {
+               (*new_url)->components.scheme_type = NSURL_SCHEME_HTTP;
+       } else if (lwc_string_caseless_isequal(scheme, corestring_lwc_https,
+                       &match) == lwc_error_ok && match == true) {
+               (*new_url)->components.scheme_type = NSURL_SCHEME_HTTPS;
+       } else if (lwc_string_caseless_isequal(scheme, corestring_lwc_file,
+                       &match) == lwc_error_ok && match == true) {
+               (*new_url)->components.scheme_type = NSURL_SCHEME_FILE;
+       } else if (lwc_string_caseless_isequal(scheme, corestring_lwc_ftp,
+                       &match) == lwc_error_ok && match == true) {
+               (*new_url)->components.scheme_type = NSURL_SCHEME_FTP;
+       } else if (lwc_string_caseless_isequal(scheme, corestring_lwc_mailto,
+                       &match) == lwc_error_ok && match == true) {
+               (*new_url)->components.scheme_type = NSURL_SCHEME_MAILTO;
+       } else {
+               (*new_url)->components.scheme_type = NSURL_SCHEME_OTHER;
+       }
+
+       /* Get the nsurl's hash */
+       nsurl__calc_hash(*new_url);
+
+       /* Give the URL a reference */
+       (*new_url)->count = 1;
+
+       return NSERROR_OK;
+}
+
+
 /* exported interface documented in utils/nsurl.h */
 nserror nsurl_nice(const nsurl *url, char **result, bool remove_extensions)
 {


commitdiff 
http://git.netsurf-browser.org/netsurf.git/commit/?id=91d1f66cdefb68b2f1859037756c78a25760532d
commit 91d1f66cdefb68b2f1859037756c78a25760532d
Author: John-Mark Bell <[email protected]>
Commit: John-Mark Bell <[email protected]>

    HSTS: support policy in urldb

diff --git a/content/urldb.c b/content/urldb.c
index cacc475..1bf2233 100644
--- a/content/urldb.c
+++ b/content/urldb.c
@@ -108,6 +108,7 @@
 #include "utils/time.h"
 #include "utils/nsurl.h"
 #include "utils/ascii.h"
+#include "utils/http.h"
 #include "netsurf/bitmap.h"
 #include "desktop/cookie_manager.h"
 #include "desktop/gui_internal.h"
@@ -222,6 +223,11 @@ struct path_data {
        struct path_data *last; /**< Last child */
 };
 
+struct hsts_data {
+       time_t expires; /**< Expiry time */
+       bool include_sub_domains; /**< Whether to include subdomains */
+};
+
 struct host_part {
        /**
         * Known paths on this host. This _must_ be first so that
@@ -233,6 +239,8 @@ struct host_part {
         * without verifying certificate authenticity
         */
        bool permit_invalid_certs;
+       /* HSTS data */
+       struct hsts_data hsts;
 
        /**
         * Part of host string
@@ -290,7 +298,7 @@ static int loaded_cookie_file_version;
 /** Minimum URL database file version */
 #define MIN_URL_FILE_VERSION 106
 /** Current URL database file version */
-#define URL_FILE_VERSION 106
+#define URL_FILE_VERSION 107
 
 /**
  * filter for url presence in database
@@ -511,7 +519,8 @@ static void urldb_save_search_tree(struct search_node 
*parent, FILE *fp)
        unsigned int path_count = 0;
        char *path, *p, *end;
        int path_alloc = 64, path_used = 1;
-       time_t expiry;
+       time_t expiry, hsts_expiry = 0;
+       int hsts_include_subdomains = 0;
 
        expiry = time(NULL) - ((60 * 60 * 24) * nsoption_int(expire_url));
 
@@ -537,13 +546,25 @@ static void urldb_save_search_tree(struct search_node 
*parent, FILE *fp)
                p += written;
        }
 
+       h = parent->data;
+       if (h && h->hsts.expires > expiry) {
+               hsts_expiry = h->hsts.expires;
+               hsts_include_subdomains = h->hsts.include_sub_domains;
+       }
+
        urldb_count_urls(&parent->data->paths, expiry, &path_count);
 
        if (path_count > 0) {
-               fprintf(fp, "%s\n%i\n", host, path_count);
+               fprintf(fp, "%s %i ", host, hsts_include_subdomains);
+               urldb_write_timet(fp, hsts_expiry);
+               fprintf(fp, "%i\n", path_count);
 
                urldb_write_paths(&parent->data->paths, host, fp,
                                  &path, &path_alloc, &path_used, expiry);
+       } else if (hsts_expiry) {
+               fprintf(fp, "%s %i ", host, hsts_include_subdomains);
+               urldb_write_timet(fp, hsts_expiry);
+               fprintf(fp, "0\n");
        }
 
        free(path);
@@ -2894,6 +2915,9 @@ nserror urldb_load(const char *filename)
        }
 
        while (fgets(host, sizeof host, fp)) {
+               time_t hsts_expiry = 0;
+               int hsts_include_sub_domains = 0;
+
                /* get the hostname */
                length = strlen(host) - 1;
                host[length] = '\0';
@@ -2911,6 +2935,25 @@ nserror urldb_load(const char *filename)
                        continue;
                }
 
+               if (version >= 107) {
+                       char *p = host;
+                       while (*p && *p != ' ') p++;
+                       while (*p && *p == ' ') { *p = '\0'; p++; }
+                       hsts_include_sub_domains = (*p == '1');
+                       while (*p && *p != ' ') p++;
+                       while (*p && *p == ' ') p++;
+                       nsc_snptimet(p, strlen(p), &hsts_expiry);
+               }
+
+               h = urldb_add_host(host);
+               if (!h) {
+                       NSLOG(netsurf, INFO, "Failed adding host: '%s'", host);
+                       fclose(fp);
+                       return NSERROR_NOMEM;
+               }
+               h->hsts.expires = hsts_expiry;
+               h->hsts.include_sub_domains = hsts_include_sub_domains;
+
                /* read number of URLs */
                if (!fgets(s, MAXIMUM_URL_LENGTH, fp))
                        break;
@@ -2922,13 +2965,6 @@ nserror urldb_load(const char *filename)
                        continue;
                }
 
-               h = urldb_add_host(host);
-               if (!h) {
-                       NSLOG(netsurf, INFO, "Failed adding host: '%s'", host);
-                       fclose(fp);
-                       return NSERROR_NOMEM;
-               }
-
                /* load the non-corrupt data */
                for (i = 0; i < urls; i++) {
                        struct path_data *p = NULL;
@@ -3460,6 +3496,131 @@ bool urldb_get_cert_permissions(nsurl *url)
 }
 
 
+/* exported interface documented in content/urldb.h */
+bool urldb_set_hsts_policy(struct nsurl *url, const char *header)
+{
+       struct path_data *p;
+       struct host_part *h;
+       lwc_string *host;
+       time_t now = time(NULL);
+       http_strict_transport_security *sts;
+       uint32_t max_age = 0;
+       nserror error;
+
+       assert(url);
+
+       host = nsurl_get_component(url, NSURL_HOST);
+       if (host != NULL) {
+               if (urldb__host_is_ip_address(lwc_string_data(host))) {
+                       /* Host is IP: ignore */
+                       lwc_string_unref(host);
+                       return true;
+               }
+
+               lwc_string_unref(host);
+       }
+
+       /* add url, in case it's missing */
+       urldb_add_url(url);
+
+       p = urldb_find_url(url);
+       if (!p)
+               return false;
+
+       for (; p && p->parent; p = p->parent)
+               /* do nothing */;
+       assert(p);
+
+       h = (struct host_part *)p;
+       if (h->permit_invalid_certs) {
+               /* Transport is tainted: ignore */
+               return true;
+       }
+
+       error = http_parse_strict_transport_security(header, &sts);
+       if (error != NSERROR_OK) {
+               /* Parse failed: ignore */
+               return true;
+       }
+
+       h->hsts.include_sub_domains =
+               http_strict_transport_security_include_subdomains(sts);
+
+       max_age = http_strict_transport_security_max_age(sts);
+       if (max_age == 0) {
+               h->hsts.expires = 0;
+               h->hsts.include_sub_domains = false;
+       } else if (now + max_age > h->hsts.expires) {
+               h->hsts.expires = now + max_age;
+       }
+
+       http_strict_transport_security_destroy(sts);
+
+       return true;
+}
+
+
+/* exported interface documented in content/urldb.h */
+bool urldb_get_hsts_enabled(struct nsurl *url)
+{
+       struct path_data *p;
+       const struct host_part *h;
+       lwc_string *host;
+       time_t now = time(NULL);
+
+       assert(url);
+
+       host = nsurl_get_component(url, NSURL_HOST);
+       if (host != NULL) {
+               if (urldb__host_is_ip_address(lwc_string_data(host))) {
+                       /* Host is IP: not enabled */
+                       lwc_string_unref(host);
+                       return false;
+               } else if (lwc_string_length(host) == 0) {
+                       /* Host is blank: not enabled */
+                       lwc_string_unref(host);
+                       return false;
+               }
+
+               lwc_string_unref(host);
+       } else {
+               /* No host part: not enabled */
+               return false;
+       }
+
+       /* The URL must exist in the db in order to find HSTS policy, since
+        * we search up the tree from the URL node, and policy from further
+        * up may also apply. */
+       urldb_add_url(url);
+
+       p = urldb_find_url(url);
+       if (!p)
+               return false;
+
+       for (; p && p->parent; p = p->parent)
+               /* do nothing */;
+       assert(p);
+
+       h = (const struct host_part *)p;
+
+       /* Consult record for this host */
+       if (h->hsts.expires > now) {
+               /* Not expired */
+               return true;
+       }
+
+       /* Consult parent domains */
+       for (h = h->parent; h && h != &db_root; h = h->parent) {
+               if (h->hsts.expires > now && h->hsts.include_sub_domains) {
+                       /* Not expired and subdomains included */
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+
 /* exported interface documented in netsurf/url_db.h */
 void
 urldb_iterate_partial(const char *prefix,
diff --git a/content/urldb.h b/content/urldb.h
index 4aa5487..0ad6426 100644
--- a/content/urldb.h
+++ b/content/urldb.h
@@ -131,4 +131,22 @@ bool urldb_set_cookie(const char *header, struct nsurl 
*url, struct nsurl *refer
 char *urldb_get_cookie(struct nsurl *url, bool include_http_only);
 
 
+/**
+ * Set HSTS policy for an URL
+ *
+ * \param url URL being fetched
+ * \param header Strict-Transport-Security header value
+ * \return true on success, false otherwise
+ */
+bool urldb_set_hsts_policy(struct nsurl *url, const char *header);
+
+
+/**
+ * Determine if HSTS policy is enabled for an URL
+ *
+ * \param url URL being fetched
+ * \return true if HSTS policy is enabled, false otherwise
+ */
+bool urldb_get_hsts_enabled(struct nsurl *url);
+
 #endif


commitdiff 
http://git.netsurf-browser.org/netsurf.git/commit/?id=2de077e1bac163d3dc33c2f232354fb325cd1883
commit 2de077e1bac163d3dc33c2f232354fb325cd1883
Author: John-Mark Bell <[email protected]>
Commit: John-Mark Bell <[email protected]>

    HSTS: add parser for Strict-Transport-Security

diff --git a/utils/corestringlist.h b/utils/corestringlist.h
index def5a73..8d15eeb 100644
--- a/utils/corestringlist.h
+++ b/utils/corestringlist.h
@@ -86,6 +86,7 @@ CORESTRING_LWC_STRING(icon);
 CORESTRING_LWC_STRING(iframe);
 CORESTRING_LWC_STRING(image);
 CORESTRING_LWC_STRING(img);
+CORESTRING_LWC_STRING(includesubdomains);
 CORESTRING_LWC_STRING(input);
 CORESTRING_LWC_STRING(javascript);
 CORESTRING_LWC_STRING(justify);
@@ -141,6 +142,7 @@ CORESTRING_LWC_STRING(_top);
 /* unusual lwc strings */
 CORESTRING_LWC_VALUE(shortcut_icon, "shortcut icon");
 CORESTRING_LWC_VALUE(slash_, "/");
+CORESTRING_LWC_VALUE(max_age, "max-age");
 
 /* mime types */
 CORESTRING_LWC_VALUE(multipart_form_data, "multipart/form-data");
diff --git a/utils/http.h b/utils/http.h
index 173604f..00caf89 100644
--- a/utils/http.h
+++ b/utils/http.h
@@ -29,6 +29,7 @@
 
 #include "utils/http/content-disposition.h"
 #include "utils/http/content-type.h"
+#include "utils/http/strict-transport-security.h"
 #include "utils/http/www-authenticate.h"
 
 #endif
diff --git a/utils/http/Makefile b/utils/http/Makefile
index 198588b..f3bb765 100644
--- a/utils/http/Makefile
+++ b/utils/http/Makefile
@@ -1,6 +1,7 @@
 # http utils sources
 
 S_HTTP := challenge.c generics.c primitives.c parameter.c              \
-       content-disposition.c content-type.c www-authenticate.c
+       content-disposition.c content-type.c \
+       strict-transport-security.c www-authenticate.c
 
-S_HTTP := $(addprefix utils/http/,$(S_HTTP))
\ No newline at end of file
+S_HTTP := $(addprefix utils/http/,$(S_HTTP))
diff --git a/utils/http/challenge.c b/utils/http/challenge.c
index 578532e..9b85fcc 100644
--- a/utils/http/challenge.c
+++ b/utils/http/challenge.c
@@ -92,7 +92,7 @@ nserror http__parse_challenge(const char **input, 
http_challenge **challenge)
        http__skip_LWS(&pos);
 
        if (*pos == ',') {
-               error = http__item_list_parse(&pos, 
+               error = http__item_list_parse(&pos,
                                http__parse_parameter, first, &params);
                if (error != NSERROR_OK && error != NSERROR_NOT_FOUND) {
                        lwc_string_unref(scheme);
diff --git a/utils/http/content-disposition.c b/utils/http/content-disposition.c
index 5d5e94c..03bd12b 100644
--- a/utils/http/content-disposition.c
+++ b/utils/http/content-disposition.c
@@ -45,7 +45,7 @@ nserror http_parse_content_disposition(const char 
*header_value,
        http__skip_LWS(&pos);
 
        if (*pos == ';') {
-               error = http__item_list_parse(&pos, 
+               error = http__item_list_parse(&pos,
                                http__parse_parameter, NULL, &params);
                if (error != NSERROR_OK && error != NSERROR_NOT_FOUND) {
                        lwc_string_unref(mtype);
diff --git a/utils/http/content-type.c b/utils/http/content-type.c
index f84da8c..d4279f5 100644
--- a/utils/http/content-type.c
+++ b/utils/http/content-type.c
@@ -68,7 +68,7 @@ nserror http_parse_content_type(const char *header_value,
        http__skip_LWS(&pos);
 
        if (*pos == ';') {
-               error = http__item_list_parse(&pos, 
+               error = http__item_list_parse(&pos,
                                http__parse_parameter, NULL, &params);
                if (error != NSERROR_OK && error != NSERROR_NOT_FOUND) {
                        lwc_string_unref(subtype);
diff --git a/utils/http/generics.h b/utils/http/generics.h
index 8c391c4..a5af734 100644
--- a/utils/http/generics.h
+++ b/utils/http/generics.h
@@ -19,6 +19,8 @@
 #ifndef NETSURF_UTILS_HTTP_GENERICS_H_
 #define NETSURF_UTILS_HTTP_GENERICS_H_
 
+#include <stdbool.h>
+
 #include "utils/errors.h"
 
 /**
diff --git a/utils/http/strict-transport-security.c 
b/utils/http/strict-transport-security.c
new file mode 100644
index 0000000..64caf66
--- /dev/null
+++ b/utils/http/strict-transport-security.c
@@ -0,0 +1,336 @@
+/*
+ * Copyright 2018 John-Mark Bell <[email protected]>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <limits.h>
+#include <stdlib.h>
+
+#include "utils/corestrings.h"
+#include "utils/http.h"
+
+#include "utils/http/generics.h"
+#include "utils/http/primitives.h"
+
+/**
+ * Representation of a Strict-Transport-Security
+ */
+struct http_strict_transport_security {
+       uint32_t max_age;               /**< Max age (delta seconds) */
+       bool include_sub_domains;       /**< Whether subdomains are included */
+};
+
+/**
+ * Representation of a directive
+ */
+typedef struct http_directive {
+       http__item base;
+
+       lwc_string *name;               /**< Parameter name */
+       lwc_string *value;              /**< Parameter value (optional) */
+} http_directive;
+
+
+static void http_destroy_directive(http_directive *self)
+{
+       lwc_string_unref(self->name);
+       if (self->value != NULL) {
+               lwc_string_unref(self->value);
+       }
+       free(self);
+}
+
+static nserror http__parse_directive(const char **input,
+               http_directive **result)
+{
+       const char *pos = *input;
+       lwc_string *name;
+       lwc_string *value = NULL;
+       http_directive *directive;
+       nserror error;
+
+       /* token [ "=" ( token | quoted-string ) ] */
+
+       error = http__parse_token(&pos, &name);
+       if (error != NSERROR_OK)
+               return error;
+
+       http__skip_LWS(&pos);
+
+       if (*pos == '=') {
+               pos++;
+
+               http__skip_LWS(&pos);
+
+               if (*pos == '"')
+                       error = http__parse_quoted_string(&pos, &value);
+               else
+                       error = http__parse_token(&pos, &value);
+
+               if (error != NSERROR_OK) {
+                       lwc_string_unref(name);
+                       return error;
+               }
+       }
+
+       directive = malloc(sizeof(*directive));
+       if (directive == NULL) {
+               if (value != NULL) {
+                       lwc_string_unref(value);
+               }
+               lwc_string_unref(name);
+               return NSERROR_NOMEM;
+       }
+
+       HTTP__ITEM_INIT(directive, NULL, http_destroy_directive);
+       directive->name = name;
+       directive->value = value;
+
+       *result = directive;
+       *input = pos;
+
+       return NSERROR_OK;
+}
+
+static void http_directive_list_destroy(http_directive *list)
+{
+       http__item_list_destroy(list);
+}
+
+static nserror http_directive_list_find_item(const http_directive *list,
+               lwc_string *name, lwc_string **value)
+{
+       bool match;
+
+       while (list != NULL) {
+               if (lwc_string_caseless_isequal(name, list->name,
+                               &match) == lwc_error_ok && match)
+                       break;
+
+               list = (http_directive *) list->base.next;
+       }
+
+       if (list == NULL)
+               return NSERROR_NOT_FOUND;
+
+       if (list->value != NULL) {
+               *value = lwc_string_ref(list->value);
+       } else {
+               *value = NULL;
+       }
+
+       return NSERROR_OK;
+}
+
+static const http_directive *http_directive_list_iterate(
+               const http_directive *cur,
+               lwc_string **name, lwc_string **value)
+{
+       if (cur == NULL)
+               return NULL;
+
+       *name = lwc_string_ref(cur->name);
+       if (cur->value != NULL) {
+               *value = lwc_string_ref(cur->value);
+       } else {
+               *value = NULL;
+       }
+
+       return (http_directive *) cur->base.next;
+}
+
+static uint32_t count(const http_directive *list, lwc_string *key)
+{
+       uint32_t count = 0;
+       bool match;
+
+       while (list != NULL) {
+               if (lwc_string_caseless_isequal(key, list->name,
+                               &match) == lwc_error_ok && match) {
+                       count++;
+               }
+
+               list = (http_directive *) list->base.next;
+       }
+
+       return count;
+}
+
+static bool check_duplicates(const http_directive *directives)
+{
+       bool result = true;
+       const http_directive *key = directives;
+
+       do {
+               lwc_string *name = NULL, *value = NULL;
+
+               key = http_directive_list_iterate(key, &name, &value);
+
+               result &= (count(directives, name) == 1);
+
+               lwc_string_unref(name);
+               if (value != NULL) {
+                       lwc_string_unref(value);
+               }
+       } while (key != NULL);
+
+       return result;
+}
+
+static nserror parse_max_age(lwc_string *value, uint32_t *result)
+{
+       const char *pos = lwc_string_data(value);
+       const char *end = pos + lwc_string_length(value);
+       uint32_t val = 0;
+
+       /* 1*DIGIT */
+
+       if (pos == end) {
+               /* Blank value */
+               return NSERROR_NOT_FOUND;
+       }
+
+       while (pos < end) {
+               if ('0' <= *pos && *pos <= '9') {
+                       uint32_t nv = val * 10 + (*pos - '0');
+                       if (nv < val) {
+                               val = UINT_MAX;
+                       } else {
+                               val = nv;
+                       }
+               } else {
+                       /* Non-digit */
+                       return NSERROR_NOT_FOUND;
+               }
+
+               pos++;
+       }
+
+       *result = val;
+
+       return NSERROR_OK;
+}
+
+/* See strict-transport-security.h for documentation */
+nserror http_parse_strict_transport_security(const char *header_value,
+               http_strict_transport_security **result)
+{
+       const char *pos = header_value;
+       http_strict_transport_security *sts;
+       http_directive *first = NULL;
+       http_directive *directives = NULL;
+       lwc_string *max_age_str = NULL, *isd_str = NULL;
+       uint32_t max_age;
+       bool include_sub_domains = false;
+       nserror error;
+
+       /* directive *( ";" directive ) */
+
+       http__skip_LWS(&pos);
+
+       error = http__parse_directive(&pos, &first);
+       if (error != NSERROR_OK) {
+               return error;
+       }
+
+       http__skip_LWS(&pos);
+
+       if (*pos == ';') {
+               error = http__item_list_parse(&pos,
+                               http__parse_directive, first, &directives);
+               if (error != NSERROR_OK) {
+                       if (directives != NULL) {
+                               http_directive_list_destroy(directives);
+                       }
+                       return error;
+               }
+       } else {
+               directives = first;
+       }
+
+       /* Each directive must only appear once */
+       if (check_duplicates(directives) == false) {
+               http_directive_list_destroy(directives);
+               return NSERROR_NOT_FOUND;
+       }
+
+       /* max-age is required */
+       error = http_directive_list_find_item(directives,
+                       corestring_lwc_max_age, &max_age_str);
+       if (error != NSERROR_OK || max_age_str == NULL) {
+               http_directive_list_destroy(directives);
+               return NSERROR_NOT_FOUND;
+       }
+
+       error = parse_max_age(max_age_str, &max_age);
+       if (error != NSERROR_OK) {
+               lwc_string_unref(max_age_str);
+               http_directive_list_destroy(directives);
+               return NSERROR_NOT_FOUND;
+       }
+       lwc_string_unref(max_age_str);
+
+       /* includeSubDomains is optional and valueless */
+       error = http_directive_list_find_item(directives,
+                       corestring_lwc_includesubdomains, &isd_str);
+       if (error != NSERROR_OK && error != NSERROR_NOT_FOUND) {
+               http_directive_list_destroy(directives);
+               return NSERROR_NOT_FOUND;
+       } else if (error == NSERROR_OK) {
+               if (isd_str != NULL) {
+                       /* Present, but not valueless: invalid */
+                       lwc_string_unref(isd_str);
+                       http_directive_list_destroy(directives);
+                       return NSERROR_NOT_FOUND;
+               }
+               include_sub_domains = true;
+       }
+       http_directive_list_destroy(directives);
+
+       sts = malloc(sizeof(*sts));
+       if (sts == NULL) {
+               return NSERROR_NOMEM;
+       }
+
+       sts->max_age = max_age;
+       sts->include_sub_domains = include_sub_domains;
+
+       *result = sts;
+
+       return NSERROR_OK;
+}
+
+/* See strict-transport-security.h for documentation */
+void http_strict_transport_security_destroy(
+               http_strict_transport_security *victim)
+{
+       free(victim);
+}
+
+/* See strict-transport-security.h for documentation */
+uint32_t http_strict_transport_security_max_age(
+               http_strict_transport_security *sts)
+{
+       return sts->max_age;
+}
+
+/* See strict-transport-security.h for documentation */
+bool http_strict_transport_security_include_subdomains(
+               http_strict_transport_security *sts)
+{
+       return sts->include_sub_domains;
+}
+
diff --git a/utils/http/strict-transport-security.h 
b/utils/http/strict-transport-security.h
new file mode 100644
index 0000000..4e52419
--- /dev/null
+++ b/utils/http/strict-transport-security.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2018 John-Mark Bell <[email protected]>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NETSURF_UTILS_HTTP_STRICT_TRANSPORT_SECURITY_H_
+#define NETSURF_UTILS_HTTP_STRICT_TRANSPORT_SECURITY_H_
+
+#include <libwapcaplet/libwapcaplet.h>
+
+typedef struct http_strict_transport_security http_strict_transport_security;
+
+/**
+ * Parse an HTTP Strict-Transport-Security header value
+ *
+ * \param header_value  Header value to parse
+ * \param result        Pointer to location to receive result
+ * \return NSERROR_OK on success,
+ *         NSERROR_NOMEM on memory exhaustion,
+ *         appropriate error otherwise
+ */
+nserror http_parse_strict_transport_security(const char *header_value,
+               http_strict_transport_security **result);
+
+/**
+ * Destroy a strict transport security object
+ *
+ * \param victim  Object to destroy
+ */
+void http_strict_transport_security_destroy(
+               http_strict_transport_security *victim);
+
+/**
+ * Get the value of a strict transport security's max-age
+ *
+ * \param sts Object to inspect
+ * \return Max age, in delta-seconds
+ */
+uint32_t http_strict_transport_security_max_age(
+               http_strict_transport_security *sts);
+
+/**
+ * Get the value of a strict transport security's includeSubDomains flag
+ *
+ * \param sts Object to inspect
+ * \return Whether subdomains should be included
+ */
+bool http_strict_transport_security_include_subdomains(
+               http_strict_transport_security *sts);
+
+#endif


commitdiff 
http://git.netsurf-browser.org/netsurf.git/commit/?id=badc0d437adff453f046cd8f0eb46c4fa5afe2bf
commit badc0d437adff453f046cd8f0eb46c4fa5afe2bf
Author: John-Mark Bell <[email protected]>
Commit: John-Mark Bell <[email protected]>

    LLCache: correct typos/grammar/etc.

diff --git a/content/llcache.c b/content/llcache.c
index 0c6f3a9..58803ea 100644
--- a/content/llcache.c
+++ b/content/llcache.c
@@ -86,7 +86,7 @@ struct llcache_handle {
 typedef struct llcache_object_user {
        llcache_handle *handle;         /**< Handle data for client */
 
-       bool iterator_target;           /**< This is the an iterator target */
+       bool iterator_target;           /**< This is the iterator target */
        bool queued_for_delete;         /**< This user is queued for deletion */
 
        struct llcache_object_user *prev;       /**< Previous in list */
@@ -126,7 +126,7 @@ typedef enum {
 } llcache_validate;
 
 /**
- * cache control value for invalid age.
+ * Cache control value for invalid age.
  */
 #define INVALID_AGE -1
 
@@ -150,7 +150,7 @@ typedef struct {
        char *value;            /**< Header value */
 } llcache_header;
 
-/** Current status of objects data */
+/** Current status of an object's data */
 typedef enum {
        LLCACHE_STATE_RAM = 0, /**< source data is stored in RAM only */
        LLCACHE_STATE_DISC, /**< source data is stored on disc */
@@ -191,7 +191,7 @@ struct llcache_object {
 
        /* Instrumentation. These elements are strictly for information
         * to improve the cache performance and to provide performance
-        * metrics. The values are non-authorative and must not be used to
+        * metrics. The values are non-authoritative and must not be used to
         * determine object lifetime etc.
         */
        time_t last_used; /**< time the last user was removed from the object */
@@ -791,7 +791,7 @@ static nserror llcache_fetch_process_header(llcache_object 
*object,
 /**
  * (Re)fetch an object
  *
- * sets up headers and attempts to start an actual fetch from the
+ * Sets up headers and attempts to start an actual fetch from the
  * fetchers system updating the llcache object with the new fetch on
  * successful start.
  *
@@ -1165,14 +1165,14 @@ llcache_object_remove_from_list(llcache_object *object, 
llcache_object **list)
 /**
  * Retrieve source data for an object from persistent store if necessary.
  *
- * If an objects source data has been placed in the persistent store
- * and the in memory copy released this will attempt to retrieve the
- * source data.
+ * If an object's source data has been placed in the persistent store
+ * and there is no in-memory copy, then attempt to retrieve the source
+ * data.
  *
  * \param object the object to operate on.
  * \return appropriate error code.
  */
-static nserror llcache_persist_retrieve(llcache_object *object)
+static nserror llcache_retrieve_persisted_data(llcache_object *object)
 {
        /* ensure the source data is present if necessary */
        if ((object->source_data != NULL) ||
@@ -1191,7 +1191,7 @@ static nserror llcache_persist_retrieve(llcache_object 
*object)
 }
 
 /**
- * Generate a serialised version of an objects metadata
+ * Generate a serialised version of an object's metadata
  *
  * The metadata includes object headers.
  *
@@ -1335,7 +1335,7 @@ operror:
 }
 
 /**
- * Deserialisation of an objects metadata.
+ * Deserialisation of an object's metadata.
  *
  * Attempt to retrieve and deserialise the metadata for an object from
  * the backing store.
@@ -1361,7 +1361,7 @@ llcache_process_metadata(llcache_object *object)
 
        size_t source_length;
        time_t request_time;
-       time_t reponse_time;
+       time_t response_time;
        time_t completion_time;
        size_t num_headers;
        size_t hloop;
@@ -1412,7 +1412,7 @@ llcache_process_metadata(llcache_object *object)
        nsurl_unref(metadataurl);
 
 
-       /* metadata line 2 is the objects length */
+       /* metadata line 2 is the object's length */
        line = 2;
        ln += lnsize + 1;
        lnsize = strlen(ln);
@@ -1438,7 +1438,7 @@ llcache_process_metadata(llcache_object *object)
        ln += lnsize + 1;
        lnsize = strlen(ln);
 
-       res = nsc_snptimet(ln, lnsize, &reponse_time);
+       res = nsc_snptimet(ln, lnsize, &response_time);
        if (res != NSERROR_OK)
                goto format_error;
 
@@ -1485,7 +1485,7 @@ llcache_process_metadata(llcache_object *object)
        object->source_alloc = metadatalen;
 
        object->cache.req_time = request_time;
-       object->cache.res_time = reponse_time;
+       object->cache.res_time = response_time;
        object->cache.fin_time = completion_time;
 
        /* object stored in backing store */
@@ -1514,7 +1514,7 @@ format_error:
  *         cache else appropriate error code.
  */
 static nserror
-llcache_object_fetch_persistant(llcache_object *object,
+llcache_object_fetch_persistent(llcache_object *object,
                                uint32_t flags,
                                nsurl *referer,
                                const llcache_post_data *post,
@@ -1604,7 +1604,7 @@ llcache_object_retrieve_from_cache(nsurl *url,
                        return error;
 
                /* attempt to retrieve object from persistent store */
-               error = llcache_object_fetch_persistant(obj, flags, referer, 
post, redirect_count);
+               error = llcache_object_fetch_persistent(obj, flags, referer, 
post, redirect_count);
                if (error == NSERROR_OK) {
                        NSLOG(llcache, DEBUG, "retrieved object from persistent 
store");
 
@@ -1631,7 +1631,7 @@ llcache_object_retrieve_from_cache(nsurl *url,
                 */
 
                /* ensure the source data is present */
-               error = llcache_persist_retrieve(newest);
+               error = llcache_retrieve_persisted_data(newest);
                if (error == NSERROR_OK) {
                        /* source data was successfully retrieved from
                         * persistent store
@@ -1658,7 +1658,7 @@ llcache_object_retrieve_from_cache(nsurl *url,
                /* Found a candidate object but it needs freshness validation */
 
                /* ensure the source data is present */
-               error = llcache_persist_retrieve(newest);
+               error = llcache_retrieve_persisted_data(newest);
                if (error == NSERROR_OK) {
 
                        /* Create a new object */
@@ -3444,8 +3444,8 @@ static void llcache_catch_up_all_users(void *ignored)
        llcache_object *object;
 
        /* Assume after this we'll be all caught up.  If any user of a handle
-        * defers then we'll end up set not caught up and we'll
-        * reschedule at that point via llcache_users_not_caught_up()
+        * defers then we'll invalidate all_caught_up and reschedule via
+        * llcache_users_not_caught_up()
         */
        llcache->all_caught_up = true;
 


-----------------------------------------------------------------------

Summary of changes:
 .gitignore                                         |   24 +++---
 Makefile                                           |   12 +--
 docs/PACKAGING-GTK                                 |    3 +-
 frontends/amiga/Makefile                           |   15 ++--
 frontends/amiga/pkg/makereslinks                   |   24 +++---
 frontends/amiga/resources/AdBlock.css              |    2 +-
 frontends/amiga/resources/ca-bundle                |    2 +-
 frontends/amiga/resources/de                       |    1 -
 frontends/amiga/resources/en                       |    1 -
 frontends/amiga/resources/fr                       |    1 -
 frontends/amiga/resources/it                       |    1 -
 frontends/amiga/resources/nl                       |    1 -
 frontends/amiga/resources/nsdefault.css            |    2 +-
 frontends/amiga/resources/quirks.css               |    2 +-
 frontends/atari/Makefile                           |   33 ++++----
 frontends/beos/res/adblock.css                     |    2 +-
 frontends/beos/res/ca-bundle.txt                   |    2 +-
 frontends/beos/res/de/welcome.html                 |    2 +-
 frontends/beos/res/default.css                     |    2 +-
 frontends/beos/res/en/credits.html                 |    2 +-
 frontends/beos/res/en/licence.html                 |    2 +-
 frontends/beos/res/en/maps.html                    |    2 +-
 frontends/beos/res/en/welcome.html                 |    2 +-
 frontends/beos/res/icons                           |    2 +-
 frontends/beos/res/internal.css                    |    2 +-
 frontends/beos/res/it/credits.html                 |    2 +-
 frontends/beos/res/it/licence.html                 |    2 +-
 frontends/beos/res/it/welcome.html                 |    2 +-
 frontends/beos/res/ja/welcome.html                 |    2 +-
 frontends/beos/res/netsurf.png                     |    2 +-
 frontends/beos/res/quirks.css                      |    2 +-
 frontends/framebuffer/Makefile                     |    3 +-
 frontends/framebuffer/res/Messages                 |    1 -
 frontends/framebuffer/res/adblock.css              |    2 +-
 frontends/framebuffer/res/credits.html             |    2 +-
 frontends/framebuffer/res/default.css              |    2 +-
 frontends/framebuffer/res/internal.css             |    2 +-
 frontends/framebuffer/res/licence.html             |    2 +-
 frontends/framebuffer/res/maps.html                |    2 +-
 frontends/framebuffer/res/netsurf.png              |    2 +-
 frontends/framebuffer/res/quirks.css               |    2 +-
 frontends/framebuffer/res/welcome.html             |    2 +-
 frontends/gtk/res/adblock.css                      |    2 +-
 frontends/gtk/res/ca-bundle.txt                    |    2 +-
 frontends/gtk/res/de/welcome.html                  |    2 +-
 frontends/gtk/res/default.css                      |    2 +-
 frontends/gtk/res/en/credits.html                  |    2 +-
 frontends/gtk/res/en/licence.html                  |    2 +-
 frontends/gtk/res/en/maps.html                     |    2 +-
 frontends/gtk/res/en/welcome.html                  |    2 +-
 frontends/gtk/res/icons                            |    2 +-
 frontends/gtk/res/internal.css                     |    2 +-
 frontends/gtk/res/it/credits.html                  |    2 +-
 frontends/gtk/res/it/licence.html                  |    2 +-
 frontends/gtk/res/it/welcome.html                  |    2 +-
 frontends/gtk/res/ja/welcome.html                  |    2 +-
 frontends/gtk/res/netsurf.png                      |    2 +-
 frontends/gtk/res/nl/credits.html                  |    2 +-
 frontends/gtk/res/nl/licence.html                  |    2 +-
 frontends/gtk/res/nl/welcome.html                  |    2 +-
 frontends/gtk/res/quirks.css                       |    2 +-
 frontends/riscos/Makefile                          |   26 +++---
 {!NetSurf => frontends/riscos/appdir}/!Boot,feb    |    0
 {!NetSurf => frontends/riscos/appdir}/!Sprites,ff9 |  Bin 1580 -> 1580 bytes
 .../riscos/appdir}/!Sprites22,ff9                  |  Bin 11528 -> 11528 bytes
 {!NetSurf => frontends/riscos/appdir}/5Sprites,ff9 |  Bin 30964 -> 30964 bytes
 .../riscos/appdir}/5Sprites11,ff9                  |  Bin 64228 -> 64228 bytes
 .../riscos/appdir}/5Sprites22,ff9                  |  Bin 40800 -> 40800 bytes
 {!NetSurf => frontends/riscos/appdir}/ASprites,ff9 |  Bin 3664 -> 3664 bytes
 .../riscos/appdir}/ASprites11,ff9                  |  Bin 15892 -> 15892 bytes
 .../riscos/appdir}/ASprites22,ff9                  |  Bin 12668 -> 12668 bytes
 .../riscos/appdir}/ChkSprites,ffb                  |  Bin 2029 -> 2029 bytes
 .../riscos/appdir}/Docs/online,b60                 |  Bin 165 -> 165 bytes
 {!NetSurf => frontends/riscos/appdir}/FixFonts,ffb |    0
 {!NetSurf => frontends/riscos/appdir}/KickNS,ffb   |  Bin 1511 -> 1511 bytes
 .../riscos/appdir}/OpenChoices,feb                 |    0
 {!NetSurf => frontends/riscos/appdir}/OpenHelp,ffb |  Bin 925 -> 925 bytes
 .../riscos/appdir}/OpenScrap,feb                   |    0
 frontends/riscos/appdir/Resources/AdBlock,f79      |    1 +
 .../riscos/appdir}/Resources/Aletheia,ffd          |  Bin 15237 -> 15237 bytes
 frontends/riscos/appdir/Resources/CSS,f79          |    1 +
 .../appdir}/Resources/Fonts/NSSymbol/Encoding      |    0
 .../Resources/Fonts/NSSymbol/IntMetrics,ff6        |  Bin 344 -> 344 bytes
 .../appdir}/Resources/Fonts/NSSymbol/Outlines,ff6  |  Bin 904 -> 904 bytes
 frontends/riscos/appdir/Resources/Icons            |    1 +
 .../riscos/appdir}/Resources/Image,ff9             |  Bin 111972 -> 111972 
bytes
 .../riscos/appdir}/Resources/LangNames             |    0
 frontends/riscos/appdir/Resources/Quirks,f79       |    1 +
 .../riscos/appdir}/Resources/SearchEngines         |    0
 .../riscos/appdir}/Resources/Sprites,ff9           |  Bin 77336 -> 77336 bytes
 frontends/riscos/appdir/Resources/ca-bundle        |    1 +
 frontends/riscos/appdir/Resources/de/Messages      |    1 +
 .../riscos/appdir/Resources/de/welcome.html,faf    |    1 +
 .../riscos/appdir}/Resources/en/!Help              |    0
 frontends/riscos/appdir/Resources/en/Messages      |    1 +
 .../riscos/appdir/Resources/en/credits.html,faf    |    1 +
 .../riscos/appdir/Resources/en/licence.html,faf    |    1 +
 frontends/riscos/appdir/Resources/en/maps.html,faf |    1 +
 .../riscos/appdir/Resources/en/welcome.html,faf    |    1 +
 frontends/riscos/appdir/Resources/fr/Messages      |    1 +
 frontends/riscos/appdir/Resources/internal.css,f79 |    1 +
 frontends/riscos/appdir/Resources/it/Messages      |    1 +
 .../riscos/appdir/Resources/it/credits.html,faf    |    1 +
 .../riscos/appdir/Resources/it/licence.html,faf    |    1 +
 .../riscos/appdir/Resources/it/welcome.html,faf    |    1 +
 .../riscos/appdir/Resources/ja/welcome.html,faf    |    1 +
 frontends/riscos/appdir/Resources/netsurf.png,b60  |    1 +
 .../riscos/appdir}/Resources/nl/!Help              |    0
 frontends/riscos/appdir/Resources/nl/Messages      |    1 +
 .../riscos/appdir/Resources/nl/credits.html,faf    |    1 +
 .../riscos/appdir/Resources/nl/licence.html,faf    |    1 +
 .../riscos/appdir/Resources/nl/welcome.html,faf    |    1 +
 frontends/windows/Makefile                         |    1 +
 frontends/windows/res/adblock.css                  |    2 +-
 frontends/windows/res/ca-bundle.crt                |    2 +-
 frontends/windows/res/credits.html                 |    2 +-
 frontends/windows/res/default.css                  |    2 +-
 frontends/windows/res/internal.css                 |    2 +-
 frontends/windows/res/licence.html                 |    2 +-
 frontends/windows/res/netsurf.png                  |    2 +-
 frontends/windows/res/quirks.css                   |    2 +-
 frontends/windows/res/welcome.html                 |    2 +-
 .../Resources/AdBlock,f79 => resources/adblock.css |    0
 {!NetSurf/Resources => resources}/ca-bundle        |    0
 .../welcome.html,faf => resources/de/welcome.html  |    0
 .../Resources/CSS,f79 => resources/default.css     |    0
 .../credits.html,faf => resources/en/credits.html  |    0
 .../licence.html,faf => resources/en/licence.html  |    0
 .../en/maps.html,faf => resources/en/maps.html     |    0
 .../welcome.html,faf => resources/en/welcome.html  |    0
 .../Icons => resources/icons}/arrow-l.png          |  Bin 284 -> 284 bytes
 .../Icons => resources/icons}/content.png          |  Bin 598 -> 598 bytes
 .../Icons => resources/icons}/directory.png        |  Bin 259 -> 259 bytes
 .../Icons => resources/icons}/directory2.png       |  Bin 336 -> 336 bytes
 .../Icons => resources/icons}/hotlist-add.png      |  Bin 356 -> 356 bytes
 .../Icons => resources/icons}/hotlist-rmv.png      |  Bin 610 -> 610 bytes
 .../Resources/Icons => resources/icons}/search.png |  Bin 536 -> 536 bytes
 .../internal.css,f79 => resources/internal.css     |    0
 .../credits.html,faf => resources/it/credits.html  |    0
 .../licence.html,faf => resources/it/licence.html  |    0
 .../welcome.html,faf => resources/it/welcome.html  |    0
 .../welcome.html,faf => resources/ja/welcome.html  |    0
 .../netsurf.png,b60 => resources/netsurf.png       |  Bin 16486 -> 16486 bytes
 .../credits.html,faf => resources/nl/credits.html  |    0
 .../licence.html,faf => resources/nl/licence.html  |    0
 .../welcome.html,faf => resources/nl/welcome.html  |    0
 .../Resources/Quirks,f79 => resources/quirks.css   |    0
 utils/merge-messages.lua                           |   83 --------------------
 utils/split-messages.pl                            |   17 +++-
 149 files changed, 167 insertions(+), 218 deletions(-)
 delete mode 120000 frontends/amiga/resources/de
 delete mode 120000 frontends/amiga/resources/en
 delete mode 120000 frontends/amiga/resources/fr
 delete mode 120000 frontends/amiga/resources/it
 delete mode 120000 frontends/amiga/resources/nl
 delete mode 120000 frontends/framebuffer/res/Messages
 rename {!NetSurf => frontends/riscos/appdir}/!Boot,feb (100%)
 rename {!NetSurf => frontends/riscos/appdir}/!Sprites,ff9 (100%)
 rename {!NetSurf => frontends/riscos/appdir}/!Sprites22,ff9 (100%)
 rename {!NetSurf => frontends/riscos/appdir}/5Sprites,ff9 (100%)
 rename {!NetSurf => frontends/riscos/appdir}/5Sprites11,ff9 (100%)
 rename {!NetSurf => frontends/riscos/appdir}/5Sprites22,ff9 (100%)
 rename {!NetSurf => frontends/riscos/appdir}/ASprites,ff9 (100%)
 rename {!NetSurf => frontends/riscos/appdir}/ASprites11,ff9 (100%)
 rename {!NetSurf => frontends/riscos/appdir}/ASprites22,ff9 (100%)
 rename {!NetSurf => frontends/riscos/appdir}/ChkSprites,ffb (100%)
 rename {!NetSurf => frontends/riscos/appdir}/Docs/online,b60 (100%)
 rename {!NetSurf => frontends/riscos/appdir}/FixFonts,ffb (100%)
 rename {!NetSurf => frontends/riscos/appdir}/KickNS,ffb (100%)
 rename {!NetSurf => frontends/riscos/appdir}/OpenChoices,feb (100%)
 rename {!NetSurf => frontends/riscos/appdir}/OpenHelp,ffb (100%)
 rename {!NetSurf => frontends/riscos/appdir}/OpenScrap,feb (100%)
 create mode 120000 frontends/riscos/appdir/Resources/AdBlock,f79
 rename {!NetSurf => frontends/riscos/appdir}/Resources/Aletheia,ffd (100%)
 create mode 120000 frontends/riscos/appdir/Resources/CSS,f79
 rename {!NetSurf => frontends/riscos/appdir}/Resources/Fonts/NSSymbol/Encoding 
(100%)
 rename {!NetSurf => 
frontends/riscos/appdir}/Resources/Fonts/NSSymbol/IntMetrics,ff6 (100%)
 rename {!NetSurf => 
frontends/riscos/appdir}/Resources/Fonts/NSSymbol/Outlines,ff6 (100%)
 create mode 120000 frontends/riscos/appdir/Resources/Icons
 rename {!NetSurf => frontends/riscos/appdir}/Resources/Image,ff9 (100%)
 rename {!NetSurf => frontends/riscos/appdir}/Resources/LangNames (100%)
 create mode 120000 frontends/riscos/appdir/Resources/Quirks,f79
 rename {!NetSurf => frontends/riscos/appdir}/Resources/SearchEngines (100%)
 rename {!NetSurf => frontends/riscos/appdir}/Resources/Sprites,ff9 (100%)
 create mode 120000 frontends/riscos/appdir/Resources/ca-bundle
 create mode 120000 frontends/riscos/appdir/Resources/de/Messages
 create mode 120000 frontends/riscos/appdir/Resources/de/welcome.html,faf
 rename {!NetSurf => frontends/riscos/appdir}/Resources/en/!Help (100%)
 create mode 120000 frontends/riscos/appdir/Resources/en/Messages
 create mode 120000 frontends/riscos/appdir/Resources/en/credits.html,faf
 create mode 120000 frontends/riscos/appdir/Resources/en/licence.html,faf
 create mode 120000 frontends/riscos/appdir/Resources/en/maps.html,faf
 create mode 120000 frontends/riscos/appdir/Resources/en/welcome.html,faf
 create mode 120000 frontends/riscos/appdir/Resources/fr/Messages
 create mode 120000 frontends/riscos/appdir/Resources/internal.css,f79
 create mode 120000 frontends/riscos/appdir/Resources/it/Messages
 create mode 120000 frontends/riscos/appdir/Resources/it/credits.html,faf
 create mode 120000 frontends/riscos/appdir/Resources/it/licence.html,faf
 create mode 120000 frontends/riscos/appdir/Resources/it/welcome.html,faf
 create mode 120000 frontends/riscos/appdir/Resources/ja/welcome.html,faf
 create mode 120000 frontends/riscos/appdir/Resources/netsurf.png,b60
 rename {!NetSurf => frontends/riscos/appdir}/Resources/nl/!Help (100%)
 create mode 120000 frontends/riscos/appdir/Resources/nl/Messages
 create mode 120000 frontends/riscos/appdir/Resources/nl/credits.html,faf
 create mode 120000 frontends/riscos/appdir/Resources/nl/licence.html,faf
 create mode 120000 frontends/riscos/appdir/Resources/nl/welcome.html,faf
 rename !NetSurf/Resources/AdBlock,f79 => resources/adblock.css (100%)
 rename {!NetSurf/Resources => resources}/ca-bundle (100%)
 rename !NetSurf/Resources/de/welcome.html,faf => resources/de/welcome.html 
(100%)
 rename !NetSurf/Resources/CSS,f79 => resources/default.css (100%)
 rename !NetSurf/Resources/en/credits.html,faf => resources/en/credits.html 
(100%)
 rename !NetSurf/Resources/en/licence.html,faf => resources/en/licence.html 
(100%)
 rename !NetSurf/Resources/en/maps.html,faf => resources/en/maps.html (100%)
 rename !NetSurf/Resources/en/welcome.html,faf => resources/en/welcome.html 
(100%)
 rename {!NetSurf/Resources/Icons => resources/icons}/arrow-l.png (100%)
 rename {!NetSurf/Resources/Icons => resources/icons}/content.png (100%)
 rename {!NetSurf/Resources/Icons => resources/icons}/directory.png (100%)
 rename {!NetSurf/Resources/Icons => resources/icons}/directory2.png (100%)
 rename {!NetSurf/Resources/Icons => resources/icons}/hotlist-add.png (100%)
 rename {!NetSurf/Resources/Icons => resources/icons}/hotlist-rmv.png (100%)
 rename {!NetSurf/Resources/Icons => resources/icons}/search.png (100%)
 rename !NetSurf/Resources/internal.css,f79 => resources/internal.css (100%)
 rename !NetSurf/Resources/it/credits.html,faf => resources/it/credits.html 
(100%)
 rename !NetSurf/Resources/it/licence.html,faf => resources/it/licence.html 
(100%)
 rename !NetSurf/Resources/it/welcome.html,faf => resources/it/welcome.html 
(100%)
 rename !NetSurf/Resources/ja/welcome.html,faf => resources/ja/welcome.html 
(100%)
 rename !NetSurf/Resources/netsurf.png,b60 => resources/netsurf.png (100%)
 rename !NetSurf/Resources/nl/credits.html,faf => resources/nl/credits.html 
(100%)
 rename !NetSurf/Resources/nl/licence.html,faf => resources/nl/licence.html 
(100%)
 rename !NetSurf/Resources/nl/welcome.html,faf => resources/nl/welcome.html 
(100%)
 rename !NetSurf/Resources/Quirks,f79 => resources/quirks.css (100%)
 delete mode 100755 utils/merge-messages.lua

diff --git a/.gitignore b/.gitignore
index 35de191..bb10ba5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,16 +1,16 @@
 *~
-\!NetSurf/!Run,feb
-\!NetSurf/!RunImage,ff8
-\!NetSurf/!Help,feb
-\!NetSurf/Resources/en/Templates,fec
-\!NetSurf/Resources/en/Messages
-\!NetSurf/Resources/fr/Templates,fec
-\!NetSurf/Resources/fr/Messages
-\!NetSurf/Resources/de/Templates,fec
-\!NetSurf/Resources/de/Messages
-\!NetSurf/Resources/nl/Templates,fec
-\!NetSurf/Resources/nl/Messages
-\!NetSurf/Resources/it/Messages
+frontends/riscos/appdir/!Run,feb
+frontends/riscos/appdir/!RunImage,ff8
+frontends/riscos/appdir/!Help,feb
+frontends/riscos/appdir/Resources/en/Templates,fec
+frontends/riscos/appdir/Resources/fr/Templates,fec
+frontends/riscos/appdir/Resources/de/Templates,fec
+frontends/riscos/appdir/Resources/nl/Templates,fec
+resources/en/Messages
+resources/fr/Messages
+resources/de/Messages
+resources/nl/Messages
+resources/it/Messages
 frontends/gtk/res/en/Messages
 frontends/gtk/res/fr/Messages
 frontends/gtk/res/de/Messages
diff --git a/Makefile b/Makefile
index 0ce9cdd..52f55d5 100644
--- a/Makefile
+++ b/Makefile
@@ -130,7 +130,7 @@ MESSAGES_FILTER=any
 # The languages in the fat messages to convert
 MESSAGES_LANGUAGES=de en fr it nl
 # The target directory for the split messages
-MESSAGES_TARGET=!NetSurf/Resources
+MESSAGES_TARGET=resources
 
 # Defaults for tools
 PERL=perl
@@ -651,16 +651,12 @@ S_COMMON := \
 # Message splitting rule generation macro
 # 1 = Language
 define split_messages
-.INTERMEDIATE:$$(MESSAGES_TARGET)/$(1)/Messages.tmp
 
-$$(MESSAGES_TARGET)/$(1)/Messages.tmp: resources/FatMessages
+$$(MESSAGES_TARGET)/$(1)/Messages: resources/FatMessages
        $$(VQ)echo "MSGSPLIT: Language: $(1) Filter: $$(MESSAGES_FILTER)"
        $$(Q)$$(MKDIR) -p $$(MESSAGES_TARGET)/$(1)
-       $$(Q)$$(SPLIT_MESSAGES) -l $(1) -p $$(MESSAGES_FILTER) -f messages -o 
$$@ $$<
-
-$$(MESSAGES_TARGET)/$(1)/Messages: $$(MESSAGES_TARGET)/$(1)/Messages.tmp
-       $$(VQ)echo "COMPRESS: $$@"
-       $$(Q)gzip -9n < $$< > $$@
+       $$(Q)$$(RM) $$@
+       $$(Q)$$(SPLIT_MESSAGES) -l $(1) -p $$(MESSAGES_FILTER) -f messages -o 
$$@ -z $$<
 
 CLEAN_MESSAGES += $$(MESSAGES_TARGET)/$(1)/Messages
 MESSAGES += $$(MESSAGES_TARGET)/$(1)/Messages
diff --git a/docs/PACKAGING-GTK b/docs/PACKAGING-GTK
index 8f67522..7436f23 100644
--- a/docs/PACKAGING-GTK
+++ b/docs/PACKAGING-GTK
@@ -24,8 +24,7 @@
 
   The GTK port of NetSurf requires access to some resources at run time.
   These are stored in gtk/res/ in the source tree.  Some of these files are
-  symlinks into the !NetSurf directory, which is the application container
-  for the native RISC OS build.  None of the other files from the !NetSurf
+  symlinks into the top level resources directory.  Not all of the files in the
   directory are required - the symlinks are used only as a way of making
   checkouts smaller and making sure changes to one set of resources updates
   the other.
diff --git a/frontends/amiga/Makefile b/frontends/amiga/Makefile
index 5089b4a..ac05d1b 100644
--- a/frontends/amiga/Makefile
+++ b/frontends/amiga/Makefile
@@ -67,8 +67,8 @@ package-amiga: netsurf.lha
 
 AMIGA_LANGUAGES := de en it ja nl
 AMIGA_PLATFORM_RESOURCES := Pointers Themes default.css default.css.info 
favicon.png LangNames mimetypes Resource.map splash.png
-AMIGA_GENERIC_RESOURCES := $(AMIGA_LANGUAGES) ca-bundle Icons
-AMIGA_RESOURCES := $(addprefix 
$(FRONTEND_SOURCE_DIR)/resources/,$(AMIGA_PLATFORM_RESOURCES)) $(addprefix 
\!NetSurf/Resources/,$(AMIGA_GENERIC_RESOURCES))
+AMIGA_GENERIC_RESOURCES := $(AMIGA_LANGUAGES) ca-bundle icons
+AMIGA_RESOURCES := $(addprefix 
$(FRONTEND_SOURCE_DIR)/resources/,$(AMIGA_PLATFORM_RESOURCES)) $(addprefix 
resources/,$(AMIGA_GENERIC_RESOURCES))
 AMIGA_DISTRIBUTION_FILES := $(FRONTEND_SOURCE_DIR)/dist/*
 AMIGA_PKG_DIR := $(FRONTEND_SOURCE_DIR)/pkg
 AMIGA_INSTALL_TARGET_DIR := NetSurf_Amiga
@@ -80,13 +80,14 @@ netsurf.lha: $(EXETARGET)
        $(Q)cp -p $(EXETARGET) $(AMIGA_INSTALL_TARGET_DIR)/NetSurf
        $(Q)$(MKDIR) $(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources
        $(Q)cp -rp $(AMIGA_RESOURCES) 
$(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources
+       $(Q)mv $(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources/icons 
$(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources/Icons
        $(Q)cp -rp $(AMIGA_DISTRIBUTION_FILES) 
$(AMIGA_INSTALL_TARGET_DIR)/NetSurf
        $(Q)cat resources/SearchEngines $(AMIGA_PKG_DIR)/SearchEngines 
>$(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources/SearchEngines
-       $(Q)cp -p \!NetSurf/Resources/AdBlock,f79 
$(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources/adblock.css
-       $(Q)cp -p \!NetSurf/Resources/CSS,f79 
$(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources/nsdefault.css
-       $(Q)cp -p \!NetSurf/Resources/internal.css,f79 
$(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources/internal.css
-       $(Q)cp -p \!NetSurf/Resources/Quirks,f79 
$(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources/quirks.css
-       $(Q)cp -p \!NetSurf/Resources/netsurf.png,b60 
$(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources/netsurf.png
+       $(Q)cp -p resources/adblock.css 
$(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources/adblock.css
+       $(Q)cp -p resources/default.css 
$(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources/nsdefault.css
+       $(Q)cp -p resources/internal.css 
$(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources/internal.css
+       $(Q)cp -p resources/quirks.css 
$(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources/quirks.css
+       $(Q)cp -p resources/netsurf.png 
$(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources/netsurf.png
        $(Q)cp -p $(AMIGA_PKG_DIR)/drawer.info 
$(AMIGA_INSTALL_TARGET_DIR)/NetSurf.info
        $(Q)cp -p $(AMIGA_PKG_DIR)/AutoInstall $(AMIGA_INSTALL_TARGET_DIR)
   ifeq ($(SUBTARGET),os3)
diff --git a/frontends/amiga/pkg/makereslinks b/frontends/amiga/pkg/makereslinks
index 4302dbd..a9f7dfb 100755
--- a/frontends/amiga/pkg/makereslinks
+++ b/frontends/amiga/pkg/makereslinks
@@ -3,26 +3,26 @@
 failat 50
 makedir Resources
 cd Resources
-makelink AdBlock.css /!NetSurf/Resources/AdBlock,f79 soft
+makelink AdBlock.css /resources/adblock.css soft
 makelink default.css /amiga/resources/default.css soft
-makelink ca-bundle /!NetSurf/Resources/ca-bundle soft
-makelink de /!NetSurf/Resources/de soft
-makelink nsdefault.css /!NetSurf/Resources/CSS,f79 soft
+makelink ca-bundle /resources/ca-bundle soft
+makelink de /resources/de soft
+makelink nsdefault.css /resources/default.css soft
 makelink favicon.png /amiga/resources/favicon.png soft
 makelink Resource.map /amiga/resources/Resource.map soft
-makelink en /!NetSurf/Resources/en soft
-makelink fr /!NetSurf/Resources/fr soft
-makelink internal.css /!NetSurf/Resources/internal.css,f79 soft
-makelink it /!NetSurf/Resources/it soft
+makelink en /resources/en soft
+makelink fr /resources/fr soft
+makelink internal.css /resources/internal.css soft
+makelink it /resources/it soft
 makelink LangNames /amiga/resources/LangNames soft
-makelink netsurf.png /!NetSurf/Resources/netsurf.png,b60 soft
-makelink nl /!NetSurf/Resources/nl soft
+makelink netsurf.png /resources/netsurf.png soft
+makelink nl /resources/nl soft
 makelink Pointers /amiga/resources/Pointers soft
-makelink quirks.css /!NetSurf/Resources/Quirks,f79 soft
+makelink quirks.css /resources/quirks.css soft
 makelink SearchEngines /amiga/resources/SearchEngines soft
 makelink splash.png /amiga/resources/splash.png soft
 makelink Themes /amiga/resources/Themes soft
 makelink mimetypes /amiga/resources/mimetypes soft
 
 /
-makelink amiga/resources/nsdefault.css //!NetSurf/Resources/CSS,f79 soft
+makelink amiga/resources/nsdefault.css //resources/default.css soft
diff --git a/frontends/amiga/resources/AdBlock.css 
b/frontends/amiga/resources/AdBlock.css
index e3811f6..0d12aaa 120000
--- a/frontends/amiga/resources/AdBlock.css
+++ b/frontends/amiga/resources/AdBlock.css
@@ -1 +1 @@
-../../!NetSurf/Resources/AdBlock,f79
\ No newline at end of file
+../../../resources/adblock.css
\ No newline at end of file
diff --git a/frontends/amiga/resources/ca-bundle 
b/frontends/amiga/resources/ca-bundle
index ad2dd6b..1187fa5 120000
--- a/frontends/amiga/resources/ca-bundle
+++ b/frontends/amiga/resources/ca-bundle
@@ -1 +1 @@
-../../!NetSurf/Resources/ca-bundle
\ No newline at end of file
+../../../resources/ca-bundle
\ No newline at end of file
diff --git a/frontends/amiga/resources/de b/frontends/amiga/resources/de
deleted file mode 120000
index 3812881..0000000
--- a/frontends/amiga/resources/de
+++ /dev/null
@@ -1 +0,0 @@
-../../!NetSurf/Resources/de
\ No newline at end of file
diff --git a/frontends/amiga/resources/en b/frontends/amiga/resources/en
deleted file mode 120000
index d1dfaa9..0000000
--- a/frontends/amiga/resources/en
+++ /dev/null
@@ -1 +0,0 @@
-../../!NetSurf/Resources/en
\ No newline at end of file
diff --git a/frontends/amiga/resources/fr b/frontends/amiga/resources/fr
deleted file mode 120000
index df1cbe3..0000000
--- a/frontends/amiga/resources/fr
+++ /dev/null
@@ -1 +0,0 @@
-../../!NetSurf/Resources/fr
\ No newline at end of file
diff --git a/frontends/amiga/resources/it b/frontends/amiga/resources/it
deleted file mode 120000
index 6177e91..0000000
--- a/frontends/amiga/resources/it
+++ /dev/null
@@ -1 +0,0 @@
-../../!NetSurf/Resources/it
\ No newline at end of file
diff --git a/frontends/amiga/resources/nl b/frontends/amiga/resources/nl
deleted file mode 120000
index a07bd04..0000000
--- a/frontends/amiga/resources/nl
+++ /dev/null
@@ -1 +0,0 @@
-../../!NetSurf/Resources/nl
\ No newline at end of file
diff --git a/frontends/amiga/resources/nsdefault.css 
b/frontends/amiga/resources/nsdefault.css
index 6d2d4da..fa3ae6c 120000
--- a/frontends/amiga/resources/nsdefault.css
+++ b/frontends/amiga/resources/nsdefault.css
@@ -1 +1 @@
-../../!NetSurf/Resources/CSS,f79
\ No newline at end of file
+../../../resources/default.css
\ No newline at end of file
diff --git a/frontends/amiga/resources/quirks.css 
b/frontends/amiga/resources/quirks.css
index d9fb803..1e752cb 120000
--- a/frontends/amiga/resources/quirks.css
+++ b/frontends/amiga/resources/quirks.css
@@ -1 +1 @@
-../../!NetSurf/Resources/Quirks,f79
\ No newline at end of file
+../../../resources/quirks.css
\ No newline at end of file
diff --git a/frontends/atari/Makefile b/frontends/atari/Makefile
index a2f27e2..585f0b2 100644
--- a/frontends/atari/Makefile
+++ b/frontends/atari/Makefile
@@ -118,8 +118,8 @@ ATARI_FONT_SOURCE_URL := 
http://ftp.gnome.org/pub/GNOME/sources/ttf-bitstream-ve
 #ATARI_FONT_SOURCE_URL := http://localhost/$(ATARI_FONT_NAME).tar.gz
 ATARI_FONT_TMP_DIR := $(DEPROOT)/../
 ATARI_FONT_SOURCE_DIR := $(ATARI_FONT_TMP_DIR)$(ATARI_FONT_NAME)/
-ATARI_GENERIC_RESOURCES := de en it ja
-ATARI_RESOURCES := $(addprefix \!NetSurf/Resources/,$(ATARI_GENERIC_RESOURCES))
+ATARI_GENERIC_RESOURCES := de en it ja nl
+ATARI_RESOURCES := $(addprefix resources/,$(ATARI_GENERIC_RESOURCES))
 
 # ----------------------------------------------------------------------------
 # Install target
@@ -168,20 +168,21 @@ endif
        $(Q)cp $(ATARI_RES_DIR)/netsurf.rsc  $(ATARI_TARGET_DIR)res/netsurf.rsc
        $(Q)cp $(ATARI_RES_DIR)/languages  $(ATARI_TARGET_DIR)res/languages
        $(Q)cp $(ATARI_RES_DIR)/icons/toolbar -R $(ATARI_TARGET_DIR)res/icons
-       $(Q)cp \!NetSurf/Resources/Icons/* -R $(ATARI_TARGET_DIR)res/icons/
-
-       $(Q)cp \!NetSurf/Resources/netsurf.png,b60 
$(ATARI_TARGET_DIR)res/netsurf.png
-       $(Q)cp \!NetSurf/Resources/AdBlock,f79 
$(ATARI_TARGET_DIR)res/adblock.css
-       $(Q)cp \!NetSurf/Resources/CSS,f79 $(ATARI_TARGET_DIR)res/default.css
-       $(Q)cp \!NetSurf/Resources/Quirks,f79 $(ATARI_TARGET_DIR)res/quirks.css
-       $(Q)cp \!NetSurf/Resources/internal.css,f79 
$(ATARI_TARGET_DIR)res/internal.css
-       $(Q)cp \!NetSurf/Resources/SearchEngines $(ATARI_TARGET_DIR)res/search
-       $(Q)cp \!NetSurf/Resources/ca-bundle $(ATARI_TARGET_DIR)res/cabundle
-       $(Q)$(SPLIT_MESSAGES) -l en -p atari -f messages resources/FatMessages 
> $(ATARI_TARGET_DIR)res/messages
-       $(Q)cp \!NetSurf/Resources/en/welcome.html,faf 
$(ATARI_TARGET_DIR)res/welcome.html
-       $(Q)cp \!NetSurf/Resources/en/maps.html,faf 
$(ATARI_TARGET_DIR)res/maps.html
-       $(Q)cp \!NetSurf/Resources/en/licence.html,faf 
$(ATARI_TARGET_DIR)res/licence.html
-       $(Q)cp \!NetSurf/Resources/en/credits.html,faf 
$(ATARI_TARGET_DIR)res/credits.html
+       $(Q)cp resources/icons/* -R $(ATARI_TARGET_DIR)res/icons/
+
+       $(Q)cp resources/netsurf.png $(ATARI_TARGET_DIR)res/netsurf.png
+       $(Q)cp resources/adblock.css $(ATARI_TARGET_DIR)res/adblock.css
+       $(Q)cp resources/default.css $(ATARI_TARGET_DIR)res/default.css
+       $(Q)cp resources/quirks.css $(ATARI_TARGET_DIR)res/quirks.css
+       $(Q)cp resources/internal.css $(ATARI_TARGET_DIR)res/internal.css
+       $(Q)cp resources/SearchEngines $(ATARI_TARGET_DIR)res/search
+       $(Q)cp resources/ca-bundle $(ATARI_TARGET_DIR)res/cabundle
+       $(Q)$(RM) $(ATARI_TARGET_DIR)res/messages
+       $(Q)$(SPLIT_MESSAGES) -l en -p atari -f messages -o 
$(ATARI_TARGET_DIR)res/messages resources/FatMessages
+       $(Q)cp resources/en/welcome.html $(ATARI_TARGET_DIR)res/welcome.html
+       $(Q)cp resources/en/maps.html $(ATARI_TARGET_DIR)res/maps.html
+       $(Q)cp resources/en/licence.html $(ATARI_TARGET_DIR)res/licence.html
+       $(Q)cp resources/en/credits.html $(ATARI_TARGET_DIR)res/credits.html
 
 # copy "Bitstream Vera" font:
        $(Q)cp $(ATARI_FONT_SOURCE_DIR)RELEASENOTES.TXT 
$(ATARI_TARGET_DIR)res/fonts/
diff --git a/frontends/beos/res/adblock.css b/frontends/beos/res/adblock.css
index ff24856..0d12aaa 120000
--- a/frontends/beos/res/adblock.css
+++ b/frontends/beos/res/adblock.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/AdBlock,f79
\ No newline at end of file
+../../../resources/adblock.css
\ No newline at end of file
diff --git a/frontends/beos/res/ca-bundle.txt b/frontends/beos/res/ca-bundle.txt
index 0b0e416..1187fa5 120000
--- a/frontends/beos/res/ca-bundle.txt
+++ b/frontends/beos/res/ca-bundle.txt
@@ -1 +1 @@
-../../../!NetSurf/Resources/ca-bundle
\ No newline at end of file
+../../../resources/ca-bundle
\ No newline at end of file
diff --git a/frontends/beos/res/de/welcome.html 
b/frontends/beos/res/de/welcome.html
index 98a53b2..b77e237 120000
--- a/frontends/beos/res/de/welcome.html
+++ b/frontends/beos/res/de/welcome.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/de/welcome.html,faf
\ No newline at end of file
+../../../../resources/de/welcome.html
\ No newline at end of file
diff --git a/frontends/beos/res/default.css b/frontends/beos/res/default.css
index a8579eb..fa3ae6c 120000
--- a/frontends/beos/res/default.css
+++ b/frontends/beos/res/default.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/CSS,f79
\ No newline at end of file
+../../../resources/default.css
\ No newline at end of file
diff --git a/frontends/beos/res/en/credits.html 
b/frontends/beos/res/en/credits.html
index 252516f..f73ecd4 120000
--- a/frontends/beos/res/en/credits.html
+++ b/frontends/beos/res/en/credits.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/en/credits.html,faf
\ No newline at end of file
+../../../../resources/en/credits.html
\ No newline at end of file
diff --git a/frontends/beos/res/en/licence.html 
b/frontends/beos/res/en/licence.html
index 79f7366..0c3b430 120000
--- a/frontends/beos/res/en/licence.html
+++ b/frontends/beos/res/en/licence.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/en/licence.html,faf
\ No newline at end of file
+../../../../resources/en/licence.html
\ No newline at end of file
diff --git a/frontends/beos/res/en/maps.html b/frontends/beos/res/en/maps.html
index bb3ffcb..507a4b2 120000
--- a/frontends/beos/res/en/maps.html
+++ b/frontends/beos/res/en/maps.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/en/maps.html,faf
\ No newline at end of file
+../../../../resources/en/maps.html
\ No newline at end of file
diff --git a/frontends/beos/res/en/welcome.html 
b/frontends/beos/res/en/welcome.html
index 6010992..543f31d 120000
--- a/frontends/beos/res/en/welcome.html
+++ b/frontends/beos/res/en/welcome.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/en/welcome.html,faf
\ No newline at end of file
+../../../../resources/en/welcome.html
\ No newline at end of file
diff --git a/frontends/beos/res/icons b/frontends/beos/res/icons
index c7f8603..94d2dc0 120000
--- a/frontends/beos/res/icons
+++ b/frontends/beos/res/icons
@@ -1 +1 @@
-../../../!NetSurf/Resources/Icons
\ No newline at end of file
+../../../resources/icons
\ No newline at end of file
diff --git a/frontends/beos/res/internal.css b/frontends/beos/res/internal.css
index 17f9f15..5583a98 120000
--- a/frontends/beos/res/internal.css
+++ b/frontends/beos/res/internal.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/internal.css,f79
\ No newline at end of file
+../../../resources/internal.css
\ No newline at end of file
diff --git a/frontends/beos/res/it/credits.html 
b/frontends/beos/res/it/credits.html
index 64b7898..2b7c995 120000
--- a/frontends/beos/res/it/credits.html
+++ b/frontends/beos/res/it/credits.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/it/credits.html,faf
\ No newline at end of file
+../../../../resources/it/credits.html
\ No newline at end of file
diff --git a/frontends/beos/res/it/licence.html 
b/frontends/beos/res/it/licence.html
index 4abc825..92afce8 120000
--- a/frontends/beos/res/it/licence.html
+++ b/frontends/beos/res/it/licence.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/it/licence.html,faf
\ No newline at end of file
+../../../../resources/it/licence.html
\ No newline at end of file
diff --git a/frontends/beos/res/it/welcome.html 
b/frontends/beos/res/it/welcome.html
index 59cef05..2673ba9 120000
--- a/frontends/beos/res/it/welcome.html
+++ b/frontends/beos/res/it/welcome.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/it/welcome.html,faf
\ No newline at end of file
+../../../../resources/it/welcome.html
\ No newline at end of file
diff --git a/frontends/beos/res/ja/welcome.html 
b/frontends/beos/res/ja/welcome.html
index a2556ee..8b603f3 120000
--- a/frontends/beos/res/ja/welcome.html
+++ b/frontends/beos/res/ja/welcome.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/ja/welcome.html,faf
\ No newline at end of file
+../../../../resources/ja/welcome.html
\ No newline at end of file
diff --git a/frontends/beos/res/netsurf.png b/frontends/beos/res/netsurf.png
index 905512c..d0ab72a 120000
--- a/frontends/beos/res/netsurf.png
+++ b/frontends/beos/res/netsurf.png
@@ -1 +1 @@
-../../../!NetSurf/Resources/netsurf.png,b60
\ No newline at end of file
+../../../resources/netsurf.png
\ No newline at end of file
diff --git a/frontends/beos/res/quirks.css b/frontends/beos/res/quirks.css
index 88aabe4..1e752cb 120000
--- a/frontends/beos/res/quirks.css
+++ b/frontends/beos/res/quirks.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/Quirks,f79
\ No newline at end of file
+../../../resources/quirks.css
\ No newline at end of file
diff --git a/frontends/framebuffer/Makefile b/frontends/framebuffer/Makefile
index 323ca6c..055ef90 100644
--- a/frontends/framebuffer/Makefile
+++ b/frontends/framebuffer/Makefile
@@ -177,7 +177,8 @@ install-framebuffer:
        $(Q)$(MKDIR) -p $(DESTDIR)$(NETSURF_FRAMEBUFFER_RESOURCES)
        $(Q)cp -v $(EXETARGET) $(DESTDIR)/$(NETSURF_FRAMEBUFFER_BIN)netsurf-fb
        $(Q)for F in $(NETSURF_FRAMEBUFFER_RESOURCE_LIST); do cp -vL 
$(FRONTEND_RESOURCES_DIR)/$$F $(DESTDIR)/$(NETSURF_FRAMEBUFFER_RESOURCES); done
-       $(Q)$(SPLIT_MESSAGES) -l en -p fb -f messages resources/FatMessages | 
gzip -9n > $(DESTDIR)$(NETSURF_FRAMEBUFFER_RESOURCES)messages
+       $(Q)$(RM) $(DESTDIR)$(NETSURF_FRAMEBUFFER_RESOURCES)messages
+       $(Q)$(SPLIT_MESSAGES) -l en -p fb -f messages -o 
$(DESTDIR)$(NETSURF_FRAMEBUFFER_RESOURCES)messages -z resources/FatMessages
 
 # ----------------------------------------------------------------------------
 # Package target
diff --git a/frontends/framebuffer/res/Messages 
b/frontends/framebuffer/res/Messages
deleted file mode 120000
index 72c9eff..0000000
--- a/frontends/framebuffer/res/Messages
+++ /dev/null
@@ -1 +0,0 @@
-../../../!NetSurf/Resources/en/Messages
\ No newline at end of file
diff --git a/frontends/framebuffer/res/adblock.css 
b/frontends/framebuffer/res/adblock.css
index ff24856..0d12aaa 120000
--- a/frontends/framebuffer/res/adblock.css
+++ b/frontends/framebuffer/res/adblock.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/AdBlock,f79
\ No newline at end of file
+../../../resources/adblock.css
\ No newline at end of file
diff --git a/frontends/framebuffer/res/credits.html 
b/frontends/framebuffer/res/credits.html
index 1ba1739..b43a1a0 120000
--- a/frontends/framebuffer/res/credits.html
+++ b/frontends/framebuffer/res/credits.html
@@ -1 +1 @@
-../../../!NetSurf/Resources/en/credits.html,faf
\ No newline at end of file
+../../../resources/en/credits.html
\ No newline at end of file
diff --git a/frontends/framebuffer/res/default.css 
b/frontends/framebuffer/res/default.css
index a8579eb..fa3ae6c 120000
--- a/frontends/framebuffer/res/default.css
+++ b/frontends/framebuffer/res/default.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/CSS,f79
\ No newline at end of file
+../../../resources/default.css
\ No newline at end of file
diff --git a/frontends/framebuffer/res/internal.css 
b/frontends/framebuffer/res/internal.css
index 17f9f15..5583a98 120000
--- a/frontends/framebuffer/res/internal.css
+++ b/frontends/framebuffer/res/internal.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/internal.css,f79
\ No newline at end of file
+../../../resources/internal.css
\ No newline at end of file
diff --git a/frontends/framebuffer/res/licence.html 
b/frontends/framebuffer/res/licence.html
index 147dd6d..c0c1e66 120000
--- a/frontends/framebuffer/res/licence.html
+++ b/frontends/framebuffer/res/licence.html
@@ -1 +1 @@
-../../../!NetSurf/Resources/en/licence.html,faf
\ No newline at end of file
+../../../resources/en/licence.html
\ No newline at end of file
diff --git a/frontends/framebuffer/res/maps.html 
b/frontends/framebuffer/res/maps.html
index 2836213..05bcdc4 120000
--- a/frontends/framebuffer/res/maps.html
+++ b/frontends/framebuffer/res/maps.html
@@ -1 +1 @@
-../../../!NetSurf/Resources/en/welcome.html,faf
\ No newline at end of file
+../../../resources/en/maps.html
\ No newline at end of file
diff --git a/frontends/framebuffer/res/netsurf.png 
b/frontends/framebuffer/res/netsurf.png
index 905512c..d0ab72a 120000
--- a/frontends/framebuffer/res/netsurf.png
+++ b/frontends/framebuffer/res/netsurf.png
@@ -1 +1 @@
-../../../!NetSurf/Resources/netsurf.png,b60
\ No newline at end of file
+../../../resources/netsurf.png
\ No newline at end of file
diff --git a/frontends/framebuffer/res/quirks.css 
b/frontends/framebuffer/res/quirks.css
index 88aabe4..1e752cb 120000
--- a/frontends/framebuffer/res/quirks.css
+++ b/frontends/framebuffer/res/quirks.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/Quirks,f79
\ No newline at end of file
+../../../resources/quirks.css
\ No newline at end of file
diff --git a/frontends/framebuffer/res/welcome.html 
b/frontends/framebuffer/res/welcome.html
index 2836213..d5220f9 120000
--- a/frontends/framebuffer/res/welcome.html
+++ b/frontends/framebuffer/res/welcome.html
@@ -1 +1 @@
-../../../!NetSurf/Resources/en/welcome.html,faf
\ No newline at end of file
+../../../resources/en/welcome.html
\ No newline at end of file
diff --git a/frontends/gtk/res/adblock.css b/frontends/gtk/res/adblock.css
index ff24856..0d12aaa 120000
--- a/frontends/gtk/res/adblock.css
+++ b/frontends/gtk/res/adblock.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/AdBlock,f79
\ No newline at end of file
+../../../resources/adblock.css
\ No newline at end of file
diff --git a/frontends/gtk/res/ca-bundle.txt b/frontends/gtk/res/ca-bundle.txt
index 0b0e416..1187fa5 120000
--- a/frontends/gtk/res/ca-bundle.txt
+++ b/frontends/gtk/res/ca-bundle.txt
@@ -1 +1 @@
-../../../!NetSurf/Resources/ca-bundle
\ No newline at end of file
+../../../resources/ca-bundle
\ No newline at end of file
diff --git a/frontends/gtk/res/de/welcome.html 
b/frontends/gtk/res/de/welcome.html
index 98a53b2..b77e237 120000
--- a/frontends/gtk/res/de/welcome.html
+++ b/frontends/gtk/res/de/welcome.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/de/welcome.html,faf
\ No newline at end of file
+../../../../resources/de/welcome.html
\ No newline at end of file
diff --git a/frontends/gtk/res/default.css b/frontends/gtk/res/default.css
index a8579eb..fa3ae6c 120000
--- a/frontends/gtk/res/default.css
+++ b/frontends/gtk/res/default.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/CSS,f79
\ No newline at end of file
+../../../resources/default.css
\ No newline at end of file
diff --git a/frontends/gtk/res/en/credits.html 
b/frontends/gtk/res/en/credits.html
index 252516f..f73ecd4 120000
--- a/frontends/gtk/res/en/credits.html
+++ b/frontends/gtk/res/en/credits.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/en/credits.html,faf
\ No newline at end of file
+../../../../resources/en/credits.html
\ No newline at end of file
diff --git a/frontends/gtk/res/en/licence.html 
b/frontends/gtk/res/en/licence.html
index 79f7366..0c3b430 120000
--- a/frontends/gtk/res/en/licence.html
+++ b/frontends/gtk/res/en/licence.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/en/licence.html,faf
\ No newline at end of file
+../../../../resources/en/licence.html
\ No newline at end of file
diff --git a/frontends/gtk/res/en/maps.html b/frontends/gtk/res/en/maps.html
index bb3ffcb..507a4b2 120000
--- a/frontends/gtk/res/en/maps.html
+++ b/frontends/gtk/res/en/maps.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/en/maps.html,faf
\ No newline at end of file
+../../../../resources/en/maps.html
\ No newline at end of file
diff --git a/frontends/gtk/res/en/welcome.html 
b/frontends/gtk/res/en/welcome.html
index 6010992..543f31d 120000
--- a/frontends/gtk/res/en/welcome.html
+++ b/frontends/gtk/res/en/welcome.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/en/welcome.html,faf
\ No newline at end of file
+../../../../resources/en/welcome.html
\ No newline at end of file
diff --git a/frontends/gtk/res/icons b/frontends/gtk/res/icons
index 187efd6..94d2dc0 120000
--- a/frontends/gtk/res/icons
+++ b/frontends/gtk/res/icons
@@ -1 +1 @@
-../../../!NetSurf/Resources/Icons/
\ No newline at end of file
+../../../resources/icons
\ No newline at end of file
diff --git a/frontends/gtk/res/internal.css b/frontends/gtk/res/internal.css
index 17f9f15..5583a98 120000
--- a/frontends/gtk/res/internal.css
+++ b/frontends/gtk/res/internal.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/internal.css,f79
\ No newline at end of file
+../../../resources/internal.css
\ No newline at end of file
diff --git a/frontends/gtk/res/it/credits.html 
b/frontends/gtk/res/it/credits.html
index 64b7898..2b7c995 120000
--- a/frontends/gtk/res/it/credits.html
+++ b/frontends/gtk/res/it/credits.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/it/credits.html,faf
\ No newline at end of file
+../../../../resources/it/credits.html
\ No newline at end of file
diff --git a/frontends/gtk/res/it/licence.html 
b/frontends/gtk/res/it/licence.html
index 4abc825..92afce8 120000
--- a/frontends/gtk/res/it/licence.html
+++ b/frontends/gtk/res/it/licence.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/it/licence.html,faf
\ No newline at end of file
+../../../../resources/it/licence.html
\ No newline at end of file
diff --git a/frontends/gtk/res/it/welcome.html 
b/frontends/gtk/res/it/welcome.html
index 59cef05..2673ba9 120000
--- a/frontends/gtk/res/it/welcome.html
+++ b/frontends/gtk/res/it/welcome.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/it/welcome.html,faf
\ No newline at end of file
+../../../../resources/it/welcome.html
\ No newline at end of file
diff --git a/frontends/gtk/res/ja/welcome.html 
b/frontends/gtk/res/ja/welcome.html
index a2556ee..8b603f3 120000
--- a/frontends/gtk/res/ja/welcome.html
+++ b/frontends/gtk/res/ja/welcome.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/ja/welcome.html,faf
\ No newline at end of file
+../../../../resources/ja/welcome.html
\ No newline at end of file
diff --git a/frontends/gtk/res/netsurf.png b/frontends/gtk/res/netsurf.png
index 905512c..d0ab72a 120000
--- a/frontends/gtk/res/netsurf.png
+++ b/frontends/gtk/res/netsurf.png
@@ -1 +1 @@
-../../../!NetSurf/Resources/netsurf.png,b60
\ No newline at end of file
+../../../resources/netsurf.png
\ No newline at end of file
diff --git a/frontends/gtk/res/nl/credits.html 
b/frontends/gtk/res/nl/credits.html
index 9c98398..71b27e4 120000
--- a/frontends/gtk/res/nl/credits.html
+++ b/frontends/gtk/res/nl/credits.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/nl/credits.html,faf
\ No newline at end of file
+../../../../resources/nl/credits.html
\ No newline at end of file
diff --git a/frontends/gtk/res/nl/licence.html 
b/frontends/gtk/res/nl/licence.html
index 8a10d20..5aaf1cb 120000
--- a/frontends/gtk/res/nl/licence.html
+++ b/frontends/gtk/res/nl/licence.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/nl/licence.html,faf
\ No newline at end of file
+../../../../resources/nl/licence.html
\ No newline at end of file
diff --git a/frontends/gtk/res/nl/welcome.html 
b/frontends/gtk/res/nl/welcome.html
index 6b2ba77..ef7a97c 120000
--- a/frontends/gtk/res/nl/welcome.html
+++ b/frontends/gtk/res/nl/welcome.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/nl/welcome.html,faf
\ No newline at end of file
+../../../../resources/nl/welcome.html
\ No newline at end of file
diff --git a/frontends/gtk/res/quirks.css b/frontends/gtk/res/quirks.css
index 88aabe4..1e752cb 120000
--- a/frontends/gtk/res/quirks.css
+++ b/frontends/gtk/res/quirks.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/Quirks,f79
\ No newline at end of file
+../../../resources/quirks.css
\ No newline at end of file
diff --git a/frontends/riscos/Makefile b/frontends/riscos/Makefile
index 84a1c93..f531b6b 100644
--- a/frontends/riscos/Makefile
+++ b/frontends/riscos/Makefile
@@ -16,7 +16,7 @@ $(eval $(call 
feature_enabled,DRAW_EXPORT,-DWITH_DRAW_EXPORT,-lpencil,Drawfile e
 
 
 TPD_RISCOS = $(foreach TPL,$(notdir $(TPL_RISCOS)), \
-               !NetSurf/Resources/$(TPL)/Templates$(TPLEXT))
+               
$(FRONTEND_SOURCE_DIR)/appdir/Resources/$(TPL)/Templates$(TPLEXT))
 
 RESOURCES = $(TPD_RISCOS)
 
@@ -68,16 +68,16 @@ S_FRONTEND := 401login.c assert.c bitmap.c buffer.c 
configure.c gui.c       \
 #   are not yet available
 SOURCES = $(S_COMMON) $(S_IMAGE) $(S_BROWSER) $(S_FRONTEND)
 
-EXETARGET := !NetSurf/!RunImage$(EXEEXT)
+EXETARGET := $(FRONTEND_SOURCE_DIR)/appdir/!RunImage$(EXEEXT)
 
 # The filter and target for split messages
 MESSAGES_FILTER=ro
 
-!NetSurf/!Run$(RUNEXT): $(FRONTEND_SOURCE_DIR)/scripts/Run $(EXETARGET)
+$(FRONTEND_SOURCE_DIR)/appdir/!Run$(RUNEXT): 
$(FRONTEND_SOURCE_DIR)/scripts/Run $(EXETARGET)
        $(VQ)echo " MAKERUN: $@"
        $(Q)$(MAKERUN) $(EXETARGET) $< $@
 
-!NetSurf/!Help$(RUNEXT): $(FRONTEND_SOURCE_DIR)/scripts/Help
+$(FRONTEND_SOURCE_DIR)/appdir/!Help$(RUNEXT): 
$(FRONTEND_SOURCE_DIR)/scripts/Help
        $(VQ)echo "      CP: $@"
        $(Q)cp $< $@
 
@@ -86,16 +86,16 @@ $(DEPROOT)/squeeze.d: $(EXETARGET)
        $(Q)$(SQUEEZE) -f -v $(EXETARGET)
        $(Q)$(TOUCH) $@
 
-POSTEXES += !NetSurf/!Run$(RUNEXT) !NetSurf/!Help$(RUNEXT) $(DEPROOT)/squeeze.d
+POSTEXES += $(FRONTEND_SOURCE_DIR)/appdir/!Run$(RUNEXT) 
$(FRONTEND_SOURCE_DIR)/appdir/!Help$(RUNEXT) $(DEPROOT)/squeeze.d
 
 
 clean-run:
-       $(VQ)echo "   CLEAN: !NetSurf/!Run$(RUNEXT)"
-       $(Q) $(RM) !NetSurf/!Run$(RUNEXT)
+       $(VQ)echo "   CLEAN: !Run$(RUNEXT)"
+       $(Q) $(RM) $(FRONTEND_SOURCE_DIR)/appdir/!Run$(RUNEXT)
 
 clean-help:
-       $(VQ)echo "   CLEAN: !NetSurf/!Help$(RUNEXT)"
-       $(Q) $(RM) !NetSurf/!Help$(RUNEXT)
+       $(VQ)echo "   CLEAN: !Help$(RUNEXT)"
+       $(Q) $(RM) $(FRONTEND_SOURCE_DIR)/appdir/!Help$(RUNEXT)
 
 CLEANS += clean-run clean-help
 
@@ -109,12 +109,12 @@ TPL_RISCOS := $(addprefix 
$(FRONTEND_SOURCE_DIR)/templates/,$(TPL_RISCOS))
 
 # Template target creation macro
 define compile_template
-!NetSurf/Resources/$(1)/Templates$$(TPLEXT): $(2)
+$(FRONTEND_SOURCE_DIR)/appdir/Resources/$(1)/Templates$$(TPLEXT): $(2)
        $$(VQ)echo "TEMPLATE: $(2)"
-       $$(Q)$$(MKDIR) -p !NetSurf/Resources/$(1)
+       $$(Q)$$(MKDIR) -p $(FRONTEND_SOURCE_DIR)/appdir/Resources/$(1)
        $$(Q)$$(CC) -x c -E -P $$(CFLAGS) $(2) | $$(CCRES) - $$@
 
-CLEAN_TEMPLATES += !NetSurf/Resources/$(1)/Templates$$(TPLEXT)
+CLEAN_TEMPLATES += 
$(FRONTEND_SOURCE_DIR)/appdir/Resources/$(1)/Templates$$(TPLEXT)
 
 endef
 
@@ -142,7 +142,7 @@ package-riscos: netsurf.zip
 netsurf.zip: $(EXETARGET)
        $(eval $@_TMPDIR := $(shell mktemp -d))
        $(Q) $(RM) $@
-       $(Q) rsync --archive --verbose $(CURDIR)/!NetSurf $($@_TMPDIR)
+       $(Q) cp -rLvp $(FRONTEND_SOURCE_DIR)/appdir $($@_TMPDIR)/!NetSurf
        $(Q) $(CURDIR)/utils/git-date.sh $(FRONTEND_SOURCE_DIR)/distribution
        $(Q) rsync --archive --verbose 
$(FRONTEND_SOURCE_DIR)/distribution/!Boot $($@_TMPDIR)
        $(Q) rsync --archive --verbose 
$(FRONTEND_SOURCE_DIR)/distribution/!System $($@_TMPDIR)
diff --git a/!NetSurf/!Boot,feb b/frontends/riscos/appdir/!Boot,feb
similarity index 100%
rename from !NetSurf/!Boot,feb
rename to frontends/riscos/appdir/!Boot,feb
diff --git a/!NetSurf/!Sprites,ff9 b/frontends/riscos/appdir/!Sprites,ff9
similarity index 100%
rename from !NetSurf/!Sprites,ff9
rename to frontends/riscos/appdir/!Sprites,ff9
diff --git a/!NetSurf/!Sprites22,ff9 b/frontends/riscos/appdir/!Sprites22,ff9
similarity index 100%
rename from !NetSurf/!Sprites22,ff9
rename to frontends/riscos/appdir/!Sprites22,ff9
diff --git a/!NetSurf/5Sprites,ff9 b/frontends/riscos/appdir/5Sprites,ff9
similarity index 100%
rename from !NetSurf/5Sprites,ff9
rename to frontends/riscos/appdir/5Sprites,ff9
diff --git a/!NetSurf/5Sprites11,ff9 b/frontends/riscos/appdir/5Sprites11,ff9
similarity index 100%
rename from !NetSurf/5Sprites11,ff9
rename to frontends/riscos/appdir/5Sprites11,ff9
diff --git a/!NetSurf/5Sprites22,ff9 b/frontends/riscos/appdir/5Sprites22,ff9
similarity index 100%
rename from !NetSurf/5Sprites22,ff9
rename to frontends/riscos/appdir/5Sprites22,ff9
diff --git a/!NetSurf/ASprites,ff9 b/frontends/riscos/appdir/ASprites,ff9
similarity index 100%
rename from !NetSurf/ASprites,ff9
rename to frontends/riscos/appdir/ASprites,ff9
diff --git a/!NetSurf/ASprites11,ff9 b/frontends/riscos/appdir/ASprites11,ff9
similarity index 100%
rename from !NetSurf/ASprites11,ff9
rename to frontends/riscos/appdir/ASprites11,ff9
diff --git a/!NetSurf/ASprites22,ff9 b/frontends/riscos/appdir/ASprites22,ff9
similarity index 100%
rename from !NetSurf/ASprites22,ff9
rename to frontends/riscos/appdir/ASprites22,ff9
diff --git a/!NetSurf/ChkSprites,ffb b/frontends/riscos/appdir/ChkSprites,ffb
similarity index 100%
rename from !NetSurf/ChkSprites,ffb
rename to frontends/riscos/appdir/ChkSprites,ffb
diff --git a/!NetSurf/Docs/online,b60 b/frontends/riscos/appdir/Docs/online,b60
similarity index 100%
rename from !NetSurf/Docs/online,b60
rename to frontends/riscos/appdir/Docs/online,b60
diff --git a/!NetSurf/FixFonts,ffb b/frontends/riscos/appdir/FixFonts,ffb
similarity index 100%
rename from !NetSurf/FixFonts,ffb
rename to frontends/riscos/appdir/FixFonts,ffb
diff --git a/!NetSurf/KickNS,ffb b/frontends/riscos/appdir/KickNS,ffb
similarity index 100%
rename from !NetSurf/KickNS,ffb
rename to frontends/riscos/appdir/KickNS,ffb
diff --git a/!NetSurf/OpenChoices,feb b/frontends/riscos/appdir/OpenChoices,feb
similarity index 100%
rename from !NetSurf/OpenChoices,feb
rename to frontends/riscos/appdir/OpenChoices,feb
diff --git a/!NetSurf/OpenHelp,ffb b/frontends/riscos/appdir/OpenHelp,ffb
similarity index 100%
rename from !NetSurf/OpenHelp,ffb
rename to frontends/riscos/appdir/OpenHelp,ffb
diff --git a/!NetSurf/OpenScrap,feb b/frontends/riscos/appdir/OpenScrap,feb
similarity index 100%
rename from !NetSurf/OpenScrap,feb
rename to frontends/riscos/appdir/OpenScrap,feb
diff --git a/frontends/riscos/appdir/Resources/AdBlock,f79 
b/frontends/riscos/appdir/Resources/AdBlock,f79
new file mode 120000
index 0000000..8f57c43
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/AdBlock,f79
@@ -0,0 +1 @@
+../../../../resources/adblock.css
\ No newline at end of file
diff --git a/!NetSurf/Resources/Aletheia,ffd 
b/frontends/riscos/appdir/Resources/Aletheia,ffd
similarity index 100%
rename from !NetSurf/Resources/Aletheia,ffd
rename to frontends/riscos/appdir/Resources/Aletheia,ffd
diff --git a/frontends/riscos/appdir/Resources/CSS,f79 
b/frontends/riscos/appdir/Resources/CSS,f79
new file mode 120000
index 0000000..3238d91
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/CSS,f79
@@ -0,0 +1 @@
+../../../../resources/default.css
\ No newline at end of file
diff --git a/!NetSurf/Resources/Fonts/NSSymbol/Encoding 
b/frontends/riscos/appdir/Resources/Fonts/NSSymbol/Encoding
similarity index 100%
rename from !NetSurf/Resources/Fonts/NSSymbol/Encoding
rename to frontends/riscos/appdir/Resources/Fonts/NSSymbol/Encoding
diff --git a/!NetSurf/Resources/Fonts/NSSymbol/IntMetrics,ff6 
b/frontends/riscos/appdir/Resources/Fonts/NSSymbol/IntMetrics,ff6
similarity index 100%
rename from !NetSurf/Resources/Fonts/NSSymbol/IntMetrics,ff6
rename to frontends/riscos/appdir/Resources/Fonts/NSSymbol/IntMetrics,ff6
diff --git a/!NetSurf/Resources/Fonts/NSSymbol/Outlines,ff6 
b/frontends/riscos/appdir/Resources/Fonts/NSSymbol/Outlines,ff6
similarity index 100%
rename from !NetSurf/Resources/Fonts/NSSymbol/Outlines,ff6
rename to frontends/riscos/appdir/Resources/Fonts/NSSymbol/Outlines,ff6
diff --git a/frontends/riscos/appdir/Resources/Icons 
b/frontends/riscos/appdir/Resources/Icons
new file mode 120000
index 0000000..6820377
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/Icons
@@ -0,0 +1 @@
+../../../../resources/icons
\ No newline at end of file
diff --git a/!NetSurf/Resources/Image,ff9 
b/frontends/riscos/appdir/Resources/Image,ff9
similarity index 100%
rename from !NetSurf/Resources/Image,ff9
rename to frontends/riscos/appdir/Resources/Image,ff9
diff --git a/!NetSurf/Resources/LangNames 
b/frontends/riscos/appdir/Resources/LangNames
similarity index 100%
rename from !NetSurf/Resources/LangNames
rename to frontends/riscos/appdir/Resources/LangNames
diff --git a/frontends/riscos/appdir/Resources/Quirks,f79 
b/frontends/riscos/appdir/Resources/Quirks,f79
new file mode 120000
index 0000000..995fafc
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/Quirks,f79
@@ -0,0 +1 @@
+../../../../resources/quirks.css
\ No newline at end of file
diff --git a/!NetSurf/Resources/SearchEngines 
b/frontends/riscos/appdir/Resources/SearchEngines
similarity index 100%
rename from !NetSurf/Resources/SearchEngines
rename to frontends/riscos/appdir/Resources/SearchEngines
diff --git a/!NetSurf/Resources/Sprites,ff9 
b/frontends/riscos/appdir/Resources/Sprites,ff9
similarity index 100%
rename from !NetSurf/Resources/Sprites,ff9
rename to frontends/riscos/appdir/Resources/Sprites,ff9
diff --git a/frontends/riscos/appdir/Resources/ca-bundle 
b/frontends/riscos/appdir/Resources/ca-bundle
new file mode 120000
index 0000000..2d99c75
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/ca-bundle
@@ -0,0 +1 @@
+../../../../resources/ca-bundle
\ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/de/Messages 
b/frontends/riscos/appdir/Resources/de/Messages
new file mode 120000
index 0000000..aa40606
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/de/Messages
@@ -0,0 +1 @@
+../../../../../resources/de/Messages
\ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/de/welcome.html,faf 
b/frontends/riscos/appdir/Resources/de/welcome.html,faf
new file mode 120000
index 0000000..d3cfb11
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/de/welcome.html,faf
@@ -0,0 +1 @@
+../../../../../resources/de/welcome.html
\ No newline at end of file
diff --git a/!NetSurf/Resources/en/!Help 
b/frontends/riscos/appdir/Resources/en/!Help
similarity index 100%
rename from !NetSurf/Resources/en/!Help
rename to frontends/riscos/appdir/Resources/en/!Help
diff --git a/frontends/riscos/appdir/Resources/en/Messages 
b/frontends/riscos/appdir/Resources/en/Messages
new file mode 120000
index 0000000..56c2ae2
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/en/Messages
@@ -0,0 +1 @@
+../../../../../resources/en/Messages
\ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/en/credits.html,faf 
b/frontends/riscos/appdir/Resources/en/credits.html,faf
new file mode 120000
index 0000000..7999c6c
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/en/credits.html,faf
@@ -0,0 +1 @@
+../../../../../resources/en/credits.html
\ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/en/licence.html,faf 
b/frontends/riscos/appdir/Resources/en/licence.html,faf
new file mode 120000
index 0000000..70371ad
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/en/licence.html,faf
@@ -0,0 +1 @@
+../../../../../resources/en/licence.html
\ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/en/maps.html,faf 
b/frontends/riscos/appdir/Resources/en/maps.html,faf
new file mode 120000
index 0000000..4ae4f6c
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/en/maps.html,faf
@@ -0,0 +1 @@
+../../../../../resources/en/maps.html
\ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/en/welcome.html,faf 
b/frontends/riscos/appdir/Resources/en/welcome.html,faf
new file mode 120000
index 0000000..71020bf
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/en/welcome.html,faf
@@ -0,0 +1 @@
+../../../../../resources/en/welcome.html
\ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/fr/Messages 
b/frontends/riscos/appdir/Resources/fr/Messages
new file mode 120000
index 0000000..4c321ae
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/fr/Messages
@@ -0,0 +1 @@
+../../../../../resources/fr/Messages
\ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/internal.css,f79 
b/frontends/riscos/appdir/Resources/internal.css,f79
new file mode 120000
index 0000000..c807a4d
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/internal.css,f79
@@ -0,0 +1 @@
+../../../../resources/internal.css
\ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/it/Messages 
b/frontends/riscos/appdir/Resources/it/Messages
new file mode 120000
index 0000000..7dc2ae2
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/it/Messages
@@ -0,0 +1 @@
+../../../../../resources/it/Messages
\ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/it/credits.html,faf 
b/frontends/riscos/appdir/Resources/it/credits.html,faf
new file mode 120000
index 0000000..e0bd9a2
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/it/credits.html,faf
@@ -0,0 +1 @@
+../../../../../resources/it/credits.html
\ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/it/licence.html,faf 
b/frontends/riscos/appdir/Resources/it/licence.html,faf
new file mode 120000
index 0000000..7e8c835
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/it/licence.html,faf
@@ -0,0 +1 @@
+../../../../../resources/it/licence.html
\ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/it/welcome.html,faf 
b/frontends/riscos/appdir/Resources/it/welcome.html,faf
new file mode 120000
index 0000000..6e24135
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/it/welcome.html,faf
@@ -0,0 +1 @@
+../../../../../resources/it/welcome.html
\ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/ja/welcome.html,faf 
b/frontends/riscos/appdir/Resources/ja/welcome.html,faf
new file mode 120000
index 0000000..1dfdbd7
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/ja/welcome.html,faf
@@ -0,0 +1 @@
+../../../../../resources/ja/welcome.html
\ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/netsurf.png,b60 
b/frontends/riscos/appdir/Resources/netsurf.png,b60
new file mode 120000
index 0000000..e7fa4cb
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/netsurf.png,b60
@@ -0,0 +1 @@
+../../../../resources/netsurf.png
\ No newline at end of file
diff --git a/!NetSurf/Resources/nl/!Help 
b/frontends/riscos/appdir/Resources/nl/!Help
similarity index 100%
rename from !NetSurf/Resources/nl/!Help
rename to frontends/riscos/appdir/Resources/nl/!Help
diff --git a/frontends/riscos/appdir/Resources/nl/Messages 
b/frontends/riscos/appdir/Resources/nl/Messages
new file mode 120000
index 0000000..20acc40
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/nl/Messages
@@ -0,0 +1 @@
+../../../../../resources/nl/Messages
\ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/nl/credits.html,faf 
b/frontends/riscos/appdir/Resources/nl/credits.html,faf
new file mode 120000
index 0000000..2380aa3
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/nl/credits.html,faf
@@ -0,0 +1 @@
+../../../../../resources/nl/credits.html
\ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/nl/licence.html,faf 
b/frontends/riscos/appdir/Resources/nl/licence.html,faf
new file mode 120000
index 0000000..46804ce
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/nl/licence.html,faf
@@ -0,0 +1 @@
+../../../../../resources/nl/licence.html
\ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/nl/welcome.html,faf 
b/frontends/riscos/appdir/Resources/nl/welcome.html,faf
new file mode 120000
index 0000000..6de5c4a
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/nl/welcome.html,faf
@@ -0,0 +1 @@
+../../../../../resources/nl/welcome.html
\ No newline at end of file
diff --git a/frontends/windows/Makefile b/frontends/windows/Makefile
index 50d0d4b..de01ce3 100644
--- a/frontends/windows/Makefile
+++ b/frontends/windows/Makefile
@@ -84,6 +84,7 @@ endif
 # installer messages generation
 $(OBJROOT)/messages-en: resources/FatMessages
        $(VQ)echo "MSGSPLIT: Language: en Filter: win"
+       $(Q)$(RM) $@
        $(Q)$(SPLIT_MESSAGES) -l en -p win -f messages -o $@ $<
 
 netsurf-installer.exe: $(EXETARGET) $(WIN_RES_INS_OBJ)
diff --git a/frontends/windows/res/adblock.css 
b/frontends/windows/res/adblock.css
index ff24856..0d12aaa 120000
--- a/frontends/windows/res/adblock.css
+++ b/frontends/windows/res/adblock.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/AdBlock,f79
\ No newline at end of file
+../../../resources/adblock.css
\ No newline at end of file
diff --git a/frontends/windows/res/ca-bundle.crt 
b/frontends/windows/res/ca-bundle.crt
index 0b0e416..1187fa5 120000
--- a/frontends/windows/res/ca-bundle.crt
+++ b/frontends/windows/res/ca-bundle.crt
@@ -1 +1 @@
-../../../!NetSurf/Resources/ca-bundle
\ No newline at end of file
+../../../resources/ca-bundle
\ No newline at end of file
diff --git a/frontends/windows/res/credits.html 
b/frontends/windows/res/credits.html
index 1ba1739..b43a1a0 120000
--- a/frontends/windows/res/credits.html
+++ b/frontends/windows/res/credits.html
@@ -1 +1 @@
-../../../!NetSurf/Resources/en/credits.html,faf
\ No newline at end of file
+../../../resources/en/credits.html
\ No newline at end of file
diff --git a/frontends/windows/res/default.css 
b/frontends/windows/res/default.css
index a8579eb..fa3ae6c 120000
--- a/frontends/windows/res/default.css
+++ b/frontends/windows/res/default.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/CSS,f79
\ No newline at end of file
+../../../resources/default.css
\ No newline at end of file
diff --git a/frontends/windows/res/internal.css 
b/frontends/windows/res/internal.css
index 17f9f15..5583a98 120000
--- a/frontends/windows/res/internal.css
+++ b/frontends/windows/res/internal.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/internal.css,f79
\ No newline at end of file
+../../../resources/internal.css
\ No newline at end of file
diff --git a/frontends/windows/res/licence.html 
b/frontends/windows/res/licence.html
index 147dd6d..c0c1e66 120000
--- a/frontends/windows/res/licence.html
+++ b/frontends/windows/res/licence.html
@@ -1 +1 @@
-../../../!NetSurf/Resources/en/licence.html,faf
\ No newline at end of file
+../../../resources/en/licence.html
\ No newline at end of file
diff --git a/frontends/windows/res/netsurf.png 
b/frontends/windows/res/netsurf.png
index 905512c..d0ab72a 120000
--- a/frontends/windows/res/netsurf.png
+++ b/frontends/windows/res/netsurf.png
@@ -1 +1 @@
-../../../!NetSurf/Resources/netsurf.png,b60
\ No newline at end of file
+../../../resources/netsurf.png
\ No newline at end of file
diff --git a/frontends/windows/res/quirks.css b/frontends/windows/res/quirks.css
index 88aabe4..1e752cb 120000
--- a/frontends/windows/res/quirks.css
+++ b/frontends/windows/res/quirks.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/Quirks,f79
\ No newline at end of file
+../../../resources/quirks.css
\ No newline at end of file
diff --git a/frontends/windows/res/welcome.html 
b/frontends/windows/res/welcome.html
index 2836213..d5220f9 120000
--- a/frontends/windows/res/welcome.html
+++ b/frontends/windows/res/welcome.html
@@ -1 +1 @@
-../../../!NetSurf/Resources/en/welcome.html,faf
\ No newline at end of file
+../../../resources/en/welcome.html
\ No newline at end of file
diff --git a/!NetSurf/Resources/AdBlock,f79 b/resources/adblock.css
similarity index 100%
rename from !NetSurf/Resources/AdBlock,f79
rename to resources/adblock.css
diff --git a/!NetSurf/Resources/ca-bundle b/resources/ca-bundle
similarity index 100%
rename from !NetSurf/Resources/ca-bundle
rename to resources/ca-bundle
diff --git a/!NetSurf/Resources/de/welcome.html,faf b/resources/de/welcome.html
similarity index 100%
rename from !NetSurf/Resources/de/welcome.html,faf
rename to resources/de/welcome.html
diff --git a/!NetSurf/Resources/CSS,f79 b/resources/default.css
similarity index 100%
rename from !NetSurf/Resources/CSS,f79
rename to resources/default.css
diff --git a/!NetSurf/Resources/en/credits.html,faf b/resources/en/credits.html
similarity index 100%
rename from !NetSurf/Resources/en/credits.html,faf
rename to resources/en/credits.html
diff --git a/!NetSurf/Resources/en/licence.html,faf b/resources/en/licence.html
similarity index 100%
rename from !NetSurf/Resources/en/licence.html,faf
rename to resources/en/licence.html
diff --git a/!NetSurf/Resources/en/maps.html,faf b/resources/en/maps.html
similarity index 100%
rename from !NetSurf/Resources/en/maps.html,faf
rename to resources/en/maps.html
diff --git a/!NetSurf/Resources/en/welcome.html,faf b/resources/en/welcome.html
similarity index 100%
rename from !NetSurf/Resources/en/welcome.html,faf
rename to resources/en/welcome.html
diff --git a/!NetSurf/Resources/Icons/arrow-l.png b/resources/icons/arrow-l.png
similarity index 100%
rename from !NetSurf/Resources/Icons/arrow-l.png
rename to resources/icons/arrow-l.png
diff --git a/!NetSurf/Resources/Icons/content.png b/resources/icons/content.png
similarity index 100%
rename from !NetSurf/Resources/Icons/content.png
rename to resources/icons/content.png
diff --git a/!NetSurf/Resources/Icons/directory.png 
b/resources/icons/directory.png
similarity index 100%
rename from !NetSurf/Resources/Icons/directory.png
rename to resources/icons/directory.png
diff --git a/!NetSurf/Resources/Icons/directory2.png 
b/resources/icons/directory2.png
similarity index 100%
rename from !NetSurf/Resources/Icons/directory2.png
rename to resources/icons/directory2.png
diff --git a/!NetSurf/Resources/Icons/hotlist-add.png 
b/resources/icons/hotlist-add.png
similarity index 100%
rename from !NetSurf/Resources/Icons/hotlist-add.png
rename to resources/icons/hotlist-add.png
diff --git a/!NetSurf/Resources/Icons/hotlist-rmv.png 
b/resources/icons/hotlist-rmv.png
similarity index 100%
rename from !NetSurf/Resources/Icons/hotlist-rmv.png
rename to resources/icons/hotlist-rmv.png
diff --git a/!NetSurf/Resources/Icons/search.png b/resources/icons/search.png
similarity index 100%
rename from !NetSurf/Resources/Icons/search.png
rename to resources/icons/search.png
diff --git a/!NetSurf/Resources/internal.css,f79 b/resources/internal.css
similarity index 100%
rename from !NetSurf/Resources/internal.css,f79
rename to resources/internal.css
diff --git a/!NetSurf/Resources/it/credits.html,faf b/resources/it/credits.html
similarity index 100%
rename from !NetSurf/Resources/it/credits.html,faf
rename to resources/it/credits.html
diff --git a/!NetSurf/Resources/it/licence.html,faf b/resources/it/licence.html
similarity index 100%
rename from !NetSurf/Resources/it/licence.html,faf
rename to resources/it/licence.html
diff --git a/!NetSurf/Resources/it/welcome.html,faf b/resources/it/welcome.html
similarity index 100%
rename from !NetSurf/Resources/it/welcome.html,faf
rename to resources/it/welcome.html
diff --git a/!NetSurf/Resources/ja/welcome.html,faf b/resources/ja/welcome.html
similarity index 100%
rename from !NetSurf/Resources/ja/welcome.html,faf
rename to resources/ja/welcome.html
diff --git a/!NetSurf/Resources/netsurf.png,b60 b/resources/netsurf.png
similarity index 100%
rename from !NetSurf/Resources/netsurf.png,b60
rename to resources/netsurf.png
diff --git a/!NetSurf/Resources/nl/credits.html,faf b/resources/nl/credits.html
similarity index 100%
rename from !NetSurf/Resources/nl/credits.html,faf
rename to resources/nl/credits.html
diff --git a/!NetSurf/Resources/nl/licence.html,faf b/resources/nl/licence.html
similarity index 100%
rename from !NetSurf/Resources/nl/licence.html,faf
rename to resources/nl/licence.html
diff --git a/!NetSurf/Resources/nl/welcome.html,faf b/resources/nl/welcome.html
similarity index 100%
rename from !NetSurf/Resources/nl/welcome.html,faf
rename to resources/nl/welcome.html
diff --git a/!NetSurf/Resources/Quirks,f79 b/resources/quirks.css
similarity index 100%
rename from !NetSurf/Resources/Quirks,f79
rename to resources/quirks.css
diff --git a/utils/merge-messages.lua b/utils/merge-messages.lua
deleted file mode 100755
index 3aeac69..0000000
--- a/utils/merge-messages.lua
+++ /dev/null
@@ -1,83 +0,0 @@
-#!/usr/bin/env lua5.1
-
-local lfs = require "lfs"
-
-local en_stat = assert(lfs.attributes "!NetSurf/Resources/en/Messages")
-local language = { }
-local sorted = { }
-
-io.stderr:write("loading non-en languages...\n");
-
-for dir in lfs.dir "!NetSurf/Resources" do
-   local path = "!NetSurf/Resources/" .. dir
-   if dir ~= "en" and lfs.attributes(path .. "/Messages") then
-      local f = io.open(path .. "/Messages", "r")
-      local c = 0
-      io.stderr:write(dir, ":")
-      language[dir] = { }
-      sorted[#sorted + 1] = dir
-      for l in f:lines() do
-        if l:sub(1, 1) ~= "#" then
-           local tag, msg = l:match "^([^:]*):(.*)$"
-           if tag then
-              language[dir][tag] = msg
-              c = c + 1
-           end
-        end
-      end
-      f:close()
-      io.stderr:write(tostring(c), " entries.\n")
-   end
-end
-
-table.sort(sorted)
-
-io.stderr:write("working through en...\n")
-
-local manipulators = {
-   { "^(ami.*)", "ami.%1" },
-   { "^(gtk.*)", "gtk.%1" },
-   { "^(Help.*)", "ro.%1" },
-   { "^(ARexx.*)", "ami.%1" },
-
-   { "^(.*)$", "all.%1" } -- must be last
-}
-
-local function manipulate_tag(t)
-   for _, m in ipairs(manipulators) do
-      local r, s = t:gsub(m[1], m[2])
-      if s > 0 then return r end
-   end
-   return t
-end
-
-local f = io.open("!NetSurf/Resources/en/Messages", "r")
-
-for l in f:lines() do
-   if l:sub(1,1) == "#" then
-      print(l)
-   else
-      local tag, msg = l:match "^([^:]*):(.*)$"
-      if not tag  then
-        print(l)
-      else
-        local mtag = manipulate_tag(tag)
-        io.stdout:write("en.", mtag, ":", msg, "\n")
-        for _, langname in ipairs(sorted) do
-           local trans = language[langname][tag]
-           if not trans then
-              io.stderr:write("*** language ", langname, " lacks translation 
for ", mtag, "/", tag, "\n")
-              trans = msg
-           end
-           io.stdout:write(langname, ".", mtag, ":", trans, "\n")
-           language[langname][tag] = nil
-        end
-      end
-   end
-end
-
-for _, langname in ipairs(sorted) do
-   for tag in pairs(language[langname]) do
-      io.stderr:write("*** language ", langname, " contains orphan tag ", tag, 
"\n")
-   end
-end
\ No newline at end of file
diff --git a/utils/split-messages.pl b/utils/split-messages.pl
index 570ae03..4b50dde 100644
--- a/utils/split-messages.pl
+++ b/utils/split-messages.pl
@@ -34,6 +34,8 @@ use strict;
 use Getopt::Long ();
 use Fcntl qw( O_CREAT O_EXCL O_WRONLY O_APPEND O_RDONLY O_WRONLY );
 
+use IO::Compress::Gzip;
+
 use constant GETOPT_OPTS => qw( auto_abbrev no_getopt_compat bundling );
 use constant GETOPT_SPEC =>
   qw( output|o=s
@@ -43,6 +45,7 @@ use constant GETOPT_SPEC =>
       plat|platform|p=s
       format|fmt|f=s
       warning|W=s
+      gzip|z
       help|h|? );
 
 # default option values:
@@ -214,7 +217,7 @@ sub input_stream ()
     return \*STDIN;
 }
 
-sub output_stream ()
+sub underlying_output_stream ()
 {
     if( $opt{output} )
     {
@@ -229,6 +232,18 @@ sub output_stream ()
     return \*STDOUT;
 }
 
+sub output_stream ()
+{
+    my $ofh = underlying_output_stream();
+
+    if( $opt{gzip} )
+    {
+        $ofh = new IO::Compress::Gzip( $ofh, AutoClose => 1, -Level => 9 );
+    }
+
+    return $ofh;
+}
+
 sub formatter ()
 {
     my $name = $opt{format};


-- 
NetSurf Browser

_______________________________________________
netsurf-commits mailing list
[email protected]
http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/netsurf-commits-netsurf-browser.org

Reply via email to