Added files

Index: content/fetchers/fetch_file.c
===================================================================
--- /dev/null   2009-04-16 19:17:07.000000000 +0100
+++ content/fetchers/fetch_file.c       2010-09-09 19:47:22.000000000 +0100
@@ -0,0 +1,651 @@
+/*
+ * Copyright 2010 Vincent Sanders <[email protected]>
+ *
+ * This file is part of NetSurf.
+ *
+ * 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/>.
+ */
+
+/* file: URL handling. Based on the data fetcher by Rob Kendrik */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <string.h>
+#include <strings.h>
+#include <time.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <limits.h>
+#include <stdarg.h>
+
+#include "utils/config.h"
+#include "content/dirlist.h"
+#include "content/fetch.h"
+#include "content/fetchers/fetch_file.h"
+#include "content/urldb.h"
+#include "desktop/netsurf.h"
+#include "desktop/options.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/url.h"
+#include "utils/utils.h"
+#include "utils/ring.h"
+
+/* Maximum size of read buffer */
+#define FETCH_FILE_MAX_BUF_SIZE (1024 * 1024) 
+
+/** Context for a fetch */
+struct fetch_file_context {
+       struct fetch_file_context *r_next, *r_prev;
+
+       struct fetch *fetchh; /**< Handle for this fetch */
+
+       bool aborted; /**< Flag indicating fetch has been aborted */
+       bool locked; /**< Flag indicating entry is already entered */
+
+       char *url; /**< The full url the fetch refers to */
+       char *path; /**< The actual path to be used with open() */
+
+       int fd; /**< The file descriptor of the object */
+       struct stat fstat; /**< The objects stat */
+};
+
+static struct fetch_file_context *ring = NULL;
+
+/** issue fetch callbacks with locking */
+static bool fetch_file_send_callback(fetch_msg msg, 
+               struct fetch_file_context *ctx, const void *data, 
+               unsigned long size, fetch_error_code errorcode)
+{
+       ctx->locked = true;
+       fetch_send_callback(msg, ctx->fetchh, data, size, errorcode);
+       ctx->locked = false;
+
+       return ctx->aborted;
+}
+
+static bool fetch_file_send_header(struct fetch_file_context *ctx, const char 
*fmt, ...)
+{
+       char header[64];
+       va_list ap;
+
+       va_start(ap, fmt);
+
+       vsnprintf(header, sizeof header, fmt, ap);
+
+       va_end(ap);
+
+       LOG(("%s", header));
+
+       ctx->locked = true;
+       fetch_send_callback(FETCH_HEADER, ctx->fetchh, header, strlen(header), 
FETCH_ERROR_NO_ERROR);
+       ctx->locked = false;
+
+       return ctx->aborted;
+}
+
+static bool fetch_file_send_time(struct fetch_file_context *ctx, const char 
*fmt, const time_t *val)
+{
+       char header[64];
+       struct tm btm;
+
+       gmtime_r(val, &btm);
+
+       strftime(header, sizeof header, fmt, &btm);
+
+       LOG(("%s", header));
+
+       ctx->locked = true;
+       fetch_send_callback(FETCH_HEADER, ctx->fetchh, header, strlen(header), 
FETCH_ERROR_NO_ERROR);
+       ctx->locked = false;
+
+       return ctx->aborted;
+}
+
+/** callback to initialise the file fetcher. */
+static bool fetch_file_initialise(const char *scheme)
+{
+       LOG(("fetch_file_initialise called for %s", scheme));
+       return true;
+}
+
+/** callback to initialise the file fetcher. */
+static void fetch_file_finalise(const char *scheme)
+{
+       LOG(("fetch_file_finalise called for %s", scheme));
+}
+
+/** callback to set up a file fetch context. */
+static void *
+fetch_file_setup(struct fetch *fetchh, 
+                const char *url,
+                bool only_2xx, 
+                const char *post_urlenc,
+                const struct fetch_multipart_data *post_multipart,
+                const char **headers)
+{
+       struct fetch_file_context *ctx = calloc(1, sizeof(*ctx));
+       char *path;
+       
+       if (ctx == NULL)
+               return NULL;
+               
+       ctx->fetchh = fetchh;
+
+       ctx->url = strdup(url);
+
+       url_path(url, &path);
+       if (path == NULL) {
+               free(ctx);
+               return NULL;
+       }
+
+       url_unescape(path, &ctx->path);
+       if (ctx->path == NULL) {
+               free(path);
+               free(ctx);
+               return NULL;
+       }
+
+       free(path);
+
+       RING_INSERT(ring, ctx);
+
+       LOG(("new context %p for fetch handle %p, url %s, path %s",
+            ctx, fetchh, ctx->url, ctx->path));
+       LOG(("only_2xx %d, post_urlenc %s, post_multipart %p, headers %p",  
+            only_2xx, post_urlenc, post_multipart, headers));
+       
+       return ctx;
+}
+
+/** callback to free a file fetch */
+static void fetch_file_free(void *ctx)
+{
+       struct fetch_file_context *c = ctx;
+       LOG(("context %p",ctx));
+
+       free(c->url);
+       free(c->path);
+       RING_REMOVE(ring, c);
+       free(ctx);
+}
+
+/** callback to start a file fetch */
+static bool fetch_file_start(void *ctx)
+{
+       LOG(("context %p",ctx));
+       return true;
+}
+
+/** callback to abort a file fetch */
+static void fetch_file_abort(void *ctx)
+{
+       struct fetch_file_context *c = ctx;
+       LOG(("context %p",ctx));
+
+       /* To avoid the poll loop having to deal with the fetch context
+        * disappearing from under it, we simply flag the abort here. 
+        * The poll loop itself will perform the appropriate cleanup.
+        */
+       c->aborted = true;
+}
+
+
+/** Process object as a regular file */
+static void fetch_file_process_plain(struct fetch_file_context *ctx)
+{
+       char *buf;
+       size_t buf_size;
+
+       size_t tot_read = 0;    
+       ssize_t res;
+
+       size_t size;
+
+       size = ctx->fstat.st_size;
+
+       /* set buffer size */
+       buf_size = size;
+       if (buf_size > FETCH_FILE_MAX_BUF_SIZE)
+               buf_size = FETCH_FILE_MAX_BUF_SIZE;
+
+       /* allocate the buffer storage */
+       buf = malloc(buf_size);
+       if (buf == NULL) {
+               fetch_file_send_callback(FETCH_ERROR, ctx,
+                       "Unable to allocate memory for file data buffer",
+                       0, FETCH_ERROR_MEMORY);
+               return;
+       }
+       
+       /* fetch is going to be successful */
+       fetch_set_http_code(ctx->fetchh, 200);
+
+       /* Any callback can result in the fetch being aborted.
+        * Therefore, we _must_ check for this after _every_ call to
+        * fetch_file_send_callback().
+        */
+
+       /* content type */
+       if (fetch_file_send_header(ctx, "Content-Type: %s", 
fetch_filetype(ctx->path)))
+               goto fetch_file_process_aborted;
+
+       /* content length */
+       if (fetch_file_send_header(ctx, "Content-Length: %zd", size))
+               goto fetch_file_process_aborted;
+
+       /* Set Last modified header */
+       if (fetch_file_send_time(ctx, "Last-Modified: %a, %d %b %Y %H:%M:%S 
GMT", &ctx->fstat.st_mtime))
+               goto fetch_file_process_aborted;
+
+       /* create etag */
+       if (fetch_file_send_header(ctx, "ETag: \"%10" PRId64 "\"", (int64_t) 
ctx->fstat.st_mtime))
+               goto fetch_file_process_aborted;
+
+       /* main data loop */
+       do {
+               res = read(ctx->fd, buf, buf_size);
+               if (res == -1) {
+                       fetch_file_send_callback(FETCH_ERROR, ctx, "Error 
reading file", 0, FETCH_ERROR_PARTIAL_FILE);          
+                       return;
+               }
+
+
+               if (res == 0) {
+                       fetch_file_send_callback(FETCH_ERROR, ctx, "Unexpected 
EOF reading file", 0, FETCH_ERROR_PARTIAL_FILE);         
+                       return;
+               }
+
+               tot_read += res;
+
+               if (fetch_file_send_callback(FETCH_DATA, ctx, buf, res, 
FETCH_ERROR_NO_ERROR))
+                       break;
+
+       } while (tot_read < size);
+
+       if (!ctx->aborted) 
+               fetch_file_send_callback(FETCH_FINISHED, ctx, 0, 0, 
FETCH_ERROR_NO_ERROR);
+
+fetch_file_process_aborted:
+
+       close(ctx->fd);
+       free(buf);
+       return;
+}
+
+static char *gen_nice_title(char *path)
+{
+       char *nice_path, *cnv, *tmp;
+       char *title;
+       int title_length;
+
+       /* Convert path for display */
+       nice_path = malloc(strlen(path) * 4 + 1);
+       if (!nice_path) {
+               return NULL;
+       }
+
+       /* Escape special HTML characters */
+       for (cnv = nice_path, tmp = path; *tmp != '\0'; tmp++) {
+               if (*tmp == '<') {
+                       *cnv++ = '&';
+                       *cnv++ = 'l';
+                       *cnv++ = 't';
+                       *cnv++ = ';';
+               } else if (*tmp == '>') {
+                       *cnv++ = '&';
+                       *cnv++ = 'g';
+                       *cnv++ = 't';
+                       *cnv++ = ';';
+               } else {
+                       *cnv++ = *tmp;
+               }
+       }
+       *cnv = '\0';
+
+       /* Construct a localised title string */
+       title_length = strlen(nice_path) + strlen(messages_get("FileIndex"));
+       title = malloc(title_length);
+
+       if (title == NULL) {
+               return NULL;
+       }
+
+       /* Set title to localised "Index of <nice_path>" */
+       snprintf(title, title_length, messages_get("FileIndex"), nice_path);
+
+       free(nice_path);
+
+       return title;
+}
+
+static void fetch_file_process_error(struct fetch_file_context *ctx, int code)
+{
+       char buffer[1024];
+       const char *title;
+
+       /* content is going to return error code */
+       fetch_set_http_code(ctx->fetchh, code);
+
+       /* content type */
+       if (fetch_file_send_header(ctx, "Content-Type: text/html"))
+               goto fetch_file_process_error_aborted;
+
+       switch (code) {
+       case 401:
+               title = "Permission Denied";
+               break;
+
+       case 404:
+               title = "File not found";
+               break;
+
+       default:
+               title = "Internal Error";
+       }
+
+       snprintf(buffer, sizeof buffer, 
"<html><head><title>%s</title></head><body><h1>%s</h1><p>Error %d while 
fetching file %s</p></body></html>", title, title, code,ctx->url);
+
+       if (fetch_file_send_callback(FETCH_DATA, ctx, buffer, strlen(buffer), 
FETCH_ERROR_NO_ERROR))
+               goto fetch_file_process_error_aborted;
+
+       fetch_file_send_callback(FETCH_FINISHED, ctx, 0, 0, 
FETCH_ERROR_NO_ERROR);
+
+fetch_file_process_error_aborted:
+       return;
+}
+
+static void fetch_file_process_dir(struct fetch_file_context *ctx)
+{
+       char buffer[1024]; /* Output buffer */
+       bool even = false; /* formatting flag */
+       char *title; /* pretty printed title */
+       url_func_result res; /* result from url routines */
+       char *up; /* url of parent */
+       bool compare; /* result of url compare */
+
+       DIR *scandir; /* handle for enumerating the directory */
+       struct dirent* ent; /* leaf directory entry */
+       struct stat ent_stat; /* stat result of leaf entry */
+       char datebuf[64]; /* buffer for date text */
+       char timebuf[64]; /* buffer for time text */
+       char urlpath[PATH_MAX]; /* buffer for leaf entry path */
+
+#if defined(HAVE_FDOPENDIR)
+       scandir = fdopendir(ctx->fd); 
+#else
+       /* this poses the possibility of a race where the directory
+        * has been removed from the namespace or resources for more
+        * fd are now unavailable between the previous open() and this
+        * call.
+        */
+       close(ctx->fd);
+       scandir = opendir(ctx->path);
+#endif
+
+       if (scandir == NULL) {
+               fetch_file_process_error(ctx, 500);
+               return;
+       }
+
+       /* fetch is going to be successful */
+       fetch_set_http_code(ctx->fetchh, 200);
+
+       /* content type */
+       if (fetch_file_send_header(ctx, "Content-Type: text/html"))
+               goto fetch_file_process_dir_aborted;
+
+       /* directory listing top */
+       dirlist_generate_top(buffer, sizeof buffer);
+       if (fetch_file_send_callback(FETCH_DATA, ctx, buffer, strlen(buffer), 
FETCH_ERROR_NO_ERROR))
+               goto fetch_file_process_dir_aborted;
+
+       /* directory listing title */
+       title = gen_nice_title(ctx->path);
+       dirlist_generate_title(title, buffer, sizeof buffer);
+       free(title);
+       if (fetch_file_send_callback(FETCH_DATA, ctx, buffer, strlen(buffer), 
FETCH_ERROR_NO_ERROR))
+               goto fetch_file_process_dir_aborted;
+
+       /* Print parent directory link */
+       res = url_parent(ctx->url, &up);
+       if (res == URL_FUNC_OK) {
+               res = url_compare(ctx->url, up, false, &compare);
+               if ((res == URL_FUNC_OK) && !compare) {
+                       dirlist_generate_parent_link(up, buffer, sizeof buffer);
+
+                       fetch_file_send_callback(FETCH_DATA, ctx, 
+                                                buffer, 
+                                                strlen(buffer),
+                                                FETCH_ERROR_NO_ERROR);
+
+               }
+               free(up);
+
+               if (ctx->aborted)
+                       goto fetch_file_process_dir_aborted;
+
+       }
+
+       /* directory list headings */
+       dirlist_generate_headings(buffer, sizeof buffer);
+       if (fetch_file_send_callback(FETCH_DATA, ctx, buffer, strlen(buffer), 
FETCH_ERROR_NO_ERROR))
+                       goto fetch_file_process_dir_aborted;
+
+       while ((ent = readdir(scandir)) != NULL) {
+
+               if (ent->d_name[0] == '.')
+                       continue;
+
+               snprintf(urlpath, 
+                        sizeof urlpath, 
+                        "%s%s%s", 
+                        ctx->path,
+                        (ctx->path[strlen(ctx->path) - 1] == '/')?"":"/" , 
+                        ent->d_name);
+
+               if (stat(urlpath, &ent_stat) != 0) {
+                       ent_stat.st_mode = 0;
+                       datebuf[0] = 0;
+                       timebuf[0] = 0;
+               } else {
+                       /* Get date in output format */
+                       if (strftime((char *)&datebuf, sizeof datebuf,
+                                    "%a %d %b %Y",
+                                    localtime(&ent_stat.st_mtime)) == 0) {
+                               strncpy(datebuf, "-", sizeof datebuf);
+                       }
+
+                       /* Get time in output format */
+                       if (strftime((char *)&timebuf, sizeof timebuf,
+                                    "%H:%M",
+                                    localtime(&ent_stat.st_mtime)) == 0) {
+                               strncpy(timebuf, "-", sizeof timebuf);
+                       }
+               }
+
+               if (S_ISREG(ent_stat.st_mode)) {
+                       /* regular file */
+                       dirlist_generate_row(even, 
+                                            false, 
+                                            urlpath, 
+                                            ent->d_name,
+                                            fetch_filetype(urlpath), 
+                                            ent_stat.st_size, 
+                                            datebuf, timebuf,
+                                            buffer, sizeof(buffer));
+               } else if (S_ISDIR(ent_stat.st_mode)) {
+                       /* directory */
+                       dirlist_generate_row(even, 
+                                            true, 
+                                            urlpath, 
+                                            ent->d_name,
+                                            messages_get("FileDirectory"), 
+                                            -1, 
+                                            datebuf, timebuf,
+                                            buffer, sizeof(buffer));
+               } else {
+                       /* something else */
+                       dirlist_generate_row(even, 
+                                            false, 
+                                            urlpath, 
+                                            ent->d_name,
+                                            "", 
+                                            -1, 
+                                            datebuf, timebuf,
+                                            buffer, sizeof(buffer));
+               }
+
+               if (fetch_file_send_callback(FETCH_DATA, ctx, 
+                                            buffer, 
+                                            strlen(buffer),
+                                            FETCH_ERROR_NO_ERROR))
+                       goto fetch_file_process_dir_aborted;
+
+               even = !even;
+       }
+
+       /* directory listing bottom */
+       dirlist_generate_bottom(buffer, sizeof buffer);
+       if (fetch_file_send_callback(FETCH_DATA, ctx, buffer, strlen(buffer), 
FETCH_ERROR_NO_ERROR))
+               goto fetch_file_process_dir_aborted;
+
+               
+       fetch_file_send_callback(FETCH_FINISHED, ctx, 0, 0, 
FETCH_ERROR_NO_ERROR);
+
+fetch_file_process_dir_aborted:
+
+       closedir(scandir);
+}
+
+
+/* process a file fetch */
+static void fetch_file_process(struct fetch_file_context *ctx)
+{
+       ctx->fd = open(ctx->path, O_RDONLY);
+       if (ctx->fd < 0) {
+               /* process errors as appropriate */
+               switch (errno) {
+               case EACCES:
+                       fetch_file_process_error(ctx, 401);
+                       break;
+
+               case ENOENT:
+                       fetch_file_process_error(ctx, 404);
+                       break;
+
+               default:
+                       fetch_file_process_error(ctx, 500);
+                       break;
+               }
+               return;
+       } 
+
+       if (fstat(ctx->fd, &ctx->fstat) != 0) {
+               /* process errors as appropriate */
+               close(ctx->fd);
+               fetch_file_process_error(ctx, 500);
+               return;
+       } 
+
+#ifdef fetch_curl_modified_check
+       /* f  was fetch_curl context and I cannot determine where 
f->last_modified was set */
+
+       /* Report not modified, if appropriate */
+       if (f->last_modified && f->file_etag &&
+           f->last_modified > s.st_mtime &&
+           f->file_etag == s.st_mtime) {
+               fetch_send_callback(FETCH_NOTMODIFIED, 
+                                   f->fetch_handle, 0, 0,
+                                   FETCH_ERROR_NO_ERROR);
+               return true;
+       }
+#endif 
+
+       if (S_ISDIR(ctx->fstat.st_mode)) {
+               /* directory listing */
+               fetch_file_process_dir(ctx);
+               return;
+       }
+
+       if (S_ISREG(ctx->fstat.st_mode)) {
+               /* not a file respose */
+               fetch_file_process_plain(ctx);
+               return;
+       }
+
+       close(ctx->fd);
+
+       return;
+}
+
+/** callback to poll for additional file fetch contents */
+static void fetch_file_poll(const char *scheme)
+{
+       struct fetch_file_context *c, *next;
+       
+       if (ring == NULL) return;
+       
+       /* Iterate over ring, processing each pending fetch */
+       c = ring;
+       do {
+               /* Take a copy of the next pointer as we may destroy
+                * the ring item we're currently processing */
+               next = c->r_next;
+
+               /* Ignore fetches that have been flagged as locked.
+                * This allows safe re-entrant calls to this function.
+                * Re-entrancy can occur if, as a result of a callback,
+                * the interested party causes fetch_poll() to be called 
+                * again.
+                */
+               if (c->locked == true) {
+                       continue;
+               }
+
+               LOG(("polling unlocked context %p",c));
+
+               /* Only process non-aborted fetches */
+               if (!c->aborted) {
+                       /* file fetchs can be processed in one go */
+                       fetch_file_process(c);
+               }
+
+
+               fetch_remove_from_queues(c->fetchh);
+               fetch_free(c->fetchh);
+
+               /* Advance to next ring entry, exiting if we've reached
+                * the start of the ring or the ring has become empty
+                */
+       } while ( (c = next) != ring && ring != NULL);
+}
+
+void fetch_file_register(void)
+{
+       fetch_add_fetcher("file",
+               fetch_file_initialise,
+               fetch_file_setup,
+               fetch_file_start,
+               fetch_file_abort,
+               fetch_file_free,
+               fetch_file_poll,
+               fetch_file_finalise);
+}
Index: content/fetchers/fetch_file.h
===================================================================
--- /dev/null   2009-04-16 19:17:07.000000000 +0100
+++ content/fetchers/fetch_file.h       2010-09-09 19:47:22.000000000 +0100
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2010 Vincent Sanders <[email protected]>
+ *
+ * This file is part of NetSurf.
+ *
+ * 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/>.
+ */
+
+/** \file
+ * file: URL method handler
+ */
+
+#ifndef NETSURF_CONTENT_FETCHERS_FETCH_FILE_H
+#define NETSURF_CONTENT_FETCHERS_FETCH_FILE_H
+
+void fetch_file_register(void);
+
+#endif


Changed files


 Makefile.sources              |    4 +-
 amiga/filetype.c              |    5 ---
 content/content.c             |    5 ---
 content/content_type.h        |    1 
 content/dirlist.c             |   46 +++++++++++++++++++++---------
 content/dirlist.h             |    8 ++---
 content/fetch.c               |    2 +
 content/fetchers/fetch_curl.c |   64 +++---------------------------------------
 render/box.c                  |    1 
 utils/config.h                |   16 ++++++++++
 utils/url.c                   |   21 +++++++++++++
 utils/url.h                   |    1 
 12 files changed, 84 insertions(+), 90 deletions(-)


Index: render/box.c
===================================================================
--- render/box.c        (revision 10746)
+++ render/box.c        (working copy)
@@ -1169,7 +1169,6 @@
 #ifdef WITH_PLUGIN
                        content_get_type(box->object) == CONTENT_PLUGIN ||
 #endif
-                       content_get_type(box->object) == CONTENT_DIRECTORY ||
 #ifdef WITH_THEME_INSTALL
                        content_get_type(box->object) == CONTENT_THEME ||
 #endif
Index: Makefile.sources
===================================================================
--- Makefile.sources    (revision 10746)
+++ Makefile.sources    (working copy)
@@ -6,9 +6,9 @@
 #
 
 S_CONTENT := content.c dirlist.c fetch.c hlcache.c llcache.c urldb.c   \
-       fetchers/fetch_curl.c fetchers/fetch_data.c
+       fetchers/fetch_curl.c fetchers/fetch_data.c fetchers/fetch_file.c
 S_CSS := css.c dump.c internal.c select.c utils.c
-S_RENDER := box.c box_construct.c box_normalise.c directory.c favicon.c \
+S_RENDER := box.c box_construct.c box_normalise.c favicon.c \
        font.c form.c html.c html_interaction.c html_redraw.c           \
        hubbub_binding.c imagemap.c layout.c list.c table.c textplain.c
 S_UTILS := base64.c filename.c hashtable.c http.c locale.c messages.c  \
Index: utils/config.h
===================================================================
--- utils/config.h      (revision 10746)
+++ utils/config.h      (working copy)
@@ -20,6 +20,7 @@
 #define _NETSURF_UTILS_CONFIG_H_
 
 #include <stddef.h>
+#include <dirent.h>
 
 /* Try to detect which features the target OS supports */
 
@@ -37,6 +38,21 @@
 char *strcasestr(const char *haystack, const char *needle);
 #endif
 
+/* fdopendir is actually present on most unix systems but unless
+ * _POSIX_C_SOURCE is set to 2008 it is not declared in the system
+ * headers. It is unavailable on RISC OS which requires fallback code
+ */
+#if (_POSIX_C_SOURCE - 0) >= 200809L
+#define HAVE_FDOPENDIR
+#else
+#if defined(riscos)
+#undef HAVE_FDOPENDIR
+#else
+#define HAVE_FDOPENDIR
+DIR *fdopendir(int fd);
+#endif
+#endif
+
 /* For some reason, UnixLib defines this unconditionally. 
  * Assume we're using UnixLib if building for RISC OS. */
 #if (defined(_GNU_SOURCE) || defined(riscos))
Index: utils/url.c
===================================================================
--- utils/url.c (revision 10746)
+++ utils/url.c (working copy)
@@ -902,7 +902,28 @@
        return URL_FUNC_FAILED;
 }
 
+/**
+ * Convert an escaped string to plain.
+ * \param result unescaped string owned by caller must be freed with free()
+ * \return  URL_FUNC_OK on success
+ */
+url_func_result url_unescape(const char *str, char **result)
+{
+       char *curlstr;
+       char *retstr;
 
+       curlstr = curl_unescape(str, 0);
+       retstr = strdup(curlstr);
+       curl_free(curlstr);
+
+       if (retstr == NULL) {
+               return URL_FUNC_FAILED;
+       }
+
+       *result = retstr;
+       return URL_FUNC_OK;
+}
+
 /**
  * Escape a string suitable for inclusion in an URL.
  *
Index: utils/url.h
===================================================================
--- utils/url.h (revision 10746)
+++ utils/url.h (working copy)
@@ -53,6 +53,7 @@
                bool remove_extensions);
 url_func_result url_escape(const char *unescaped, size_t toskip,
                bool sptoplus, const char *escexceptions, char **result);
+url_func_result url_unescape(const char *str, char **result);
 url_func_result url_canonical_root(const char *url, char **result);
 url_func_result url_parent(const char *url, char **result);
 url_func_result url_plq(const char *url, char **result);
Index: content/content.c
===================================================================
--- content/content.c   (revision 10746)
+++ content/content.c   (working copy)
@@ -38,7 +38,6 @@
 #include "image/bitmap.h"
 #include "desktop/browser.h"
 #include "desktop/options.h"
-#include "render/directory.h"
 #include "render/html.h"
 #include "render/textplain.h"
 #ifdef WITH_JPEG
@@ -109,7 +108,6 @@
 #ifdef WITH_BMP
        {"application/x-ico", CONTENT_ICO},
 #endif
-       {"application/x-netsurf-directory", CONTENT_DIRECTORY},
 #ifdef WITH_THEME_INSTALL
        {"application/x-netsurf-theme", CONTENT_THEME},
 #endif
@@ -344,9 +342,6 @@
                plugin_open, plugin_close, plugin_clone,
                true},
 #endif
-       {directory_create, 0, directory_convert,
-               0, directory_destroy, 0, 0, 0, 0, 0, 0, 0, directory_clone,
-               true},
 #ifdef WITH_THEME_INSTALL
        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false},
 #endif
Index: content/dirlist.c
===================================================================
--- content/dirlist.c   (revision 10746)
+++ content/dirlist.c   (working copy)
@@ -51,9 +51,10 @@
  *     dirlist_generate_bottom()
  */
 
-const char* dirlist_generate_top(void)
+bool dirlist_generate_top(char *buffer, int buffer_length)
 {
-       return  "<html>\n"
+       int error = snprintf(buffer, buffer_length,
+                            "<html>\n"
                "<head>\n"
                "<style>\n"
                "html, body { margin: 0; padding: 0; }\n"
@@ -61,7 +62,7 @@
                "h1 { padding: 5mm; margin: 0; "
                                "border-bottom: 2px solid #bcf; }\n"
                "p { padding: 2px 5mm; margin: 0; }\n"
-               "div { display: table; width: 94%; margin: 5mm auto 0 auto; "
+               "div { display: table; width: 94%%; margin: 5mm auto 0 auto; "
                                "padding: 0; }\n"
                "a, strong { display: table-row; margin: 0; padding: 0; }\n"
                "a.odd { background-color: #bcf; }\n"
@@ -74,7 +75,14 @@
                "a.dir > span.type { font-weight: bold; }\n"
                "span.size { text-align: right; padding-right: 0.3em; }\n"
                "span.size + span.size { text-align: left; "
-                               "padding-right: 0; }\n";
+                            "padding-right: 0; }\n");
+       if (error < 0 || error >= buffer_length)
+               /* Error or buffer too small */
+               return false;
+       else
+               /* OK */
+               return true;
+
 }
 
 
@@ -142,9 +150,14 @@
  *     dirlist_generate_bottom()
  */
 
-bool dirlist_generate_title(char *title, char *buffer, int buffer_length)
+bool dirlist_generate_title(const char *title, char *buffer, int buffer_length)
 {
-       int error = snprintf(buffer, buffer_length,
+       int error;
+
+       if (title == NULL)
+               title = "";
+
+       error = snprintf(buffer, buffer_length,
                        "</style>\n"
                        "<title>%s</title>\n"
                        "</head>\n"
@@ -245,7 +258,7 @@
  * \param  directory     whether this row is for a directory (or a file)
  * \param  url           url for row entry
  * \param  name                  name of row entry
- * \param  type                  MIME type of row entry
+ * \param  mimetype      MIME type of row entry
  * \param  size                  size of row entry.  If negative, size is left 
blank
  * \param  date                  date row entry was last modified
  * \param  time                  time row entry was last modified
@@ -266,7 +279,7 @@
  */
 
 bool dirlist_generate_row(bool even, bool directory, char *url, char *name,
-               char *type, long long size, char *date, char *time,
+               const char *mimetype, long long size, char *date, char *time,
                char *buffer, int buffer_length)
 {
        const char *unit;
@@ -292,7 +305,7 @@
                        "<span class=\"time\">%s</span></a>\n",
                        url, even ? "even" : "odd",
                        directory ? "dir" : "file",
-                       name, type, size_string, unit, date, time);
+                       name, mimetype, size_string, unit, date, time);
        if (error < 0 || error >= buffer_length)
                /* Error or buffer too small */
                return false;
@@ -319,11 +332,18 @@
  *     dirlist_generate_bottom()
  */
 
-const char* dirlist_generate_bottom(void)
+bool dirlist_generate_bottom(char *buffer, int buffer_length)
 {
-       return  "</div>\n"
-               "</body>\n"
-               "</html>\n";
+       int error = snprintf(buffer, buffer_length,
+                            "</div>\n"
+                            "</body>\n"
+                            "</html>\n");
+       if (error < 0 || error >= buffer_length)
+               /* Error or buffer too small */
+               return false;
+       else
+               /* OK */
+               return true;
 }
 
 
Index: content/dirlist.h
===================================================================
--- content/dirlist.h   (revision 10746)
+++ content/dirlist.h   (working copy)
@@ -33,15 +33,15 @@
 #define DIRLIST_NO_DATE_COLUMN 1 << 3
 #define DIRLIST_NO_TIME_COLUMN 1 << 4
 
-const char* dirlist_generate_top(void);
+bool dirlist_generate_top(char *buffer, int buffer_length);
 bool dirlist_generate_hide_columns(int flags, char *buffer, int buffer_length);
-bool dirlist_generate_title(char *title, char *buffer, int buffer_length);
+bool dirlist_generate_title(const char *title, char *buffer, int 
buffer_length);
 bool dirlist_generate_parent_link(char *parent, char *buffer,
                int buffer_length);
 bool dirlist_generate_headings(char *buffer, int buffer_length);
 bool dirlist_generate_row(bool even, bool directory, char *url, char *name,
-               char *type, long long size, char *date, char *time,
+               const char *mimetype, long long size, char *date, char *time,
                char *buffer, int buffer_length);
-const char* dirlist_generate_bottom(void);
+bool dirlist_generate_bottom(char *buffer, int buffer_length);
 
 #endif
Index: content/content_type.h
===================================================================
--- content/content_type.h      (revision 10746)
+++ content/content_type.h      (working copy)
@@ -59,7 +59,6 @@
 #ifdef WITH_PLUGIN
        CONTENT_PLUGIN,
 #endif
-       CONTENT_DIRECTORY,
 #ifdef WITH_THEME_INSTALL
        CONTENT_THEME,
 #endif
Index: content/fetchers/fetch_curl.c
===================================================================
--- content/fetchers/fetch_curl.c       (revision 10746)
+++ content/fetchers/fetch_curl.c       (working copy)
@@ -217,7 +217,10 @@
 
        data = curl_version_info(CURLVERSION_NOW);
 
-       for (i = 0; data->protocols[i]; i++)
+       for (i = 0; data->protocols[i]; i++) {
+               if (strcmp(data->protocols[i], "file") == 0)
+                       continue; /* do not use curl for file: */
+
                if (!fetch_add_fetcher(data->protocols[i],
                                       fetch_curl_initialise,
                                       fetch_curl_setup,
@@ -229,6 +232,7 @@
                        LOG(("Unable to register cURL fetcher for %s",
                                        data->protocols[i]));
                }
+       }
        return;
 
 curl_easy_setopt_failed:
@@ -1155,64 +1159,6 @@
                return true;
        }
 
-       /* find MIME type from filetype for local files */
-       if (strncmp(f->url, FILE_SCHEME_PREFIX, FILE_SCHEME_PREFIX_LEN) == 0) {
-               struct stat s;
-               char *url_path = url_to_path(f->url);
-
-               LOG(("Obtaining mime type for file %s", url_path));
-
-               if (url_path != NULL && stat(url_path, &s) == 0) {
-                       /* file: URL and file exists */
-                       char header[64];
-                       const char *type;
-
-                       /* create etag */
-                       snprintf(header, sizeof header,
-                                       "ETag: \"%10" PRId64 "\"", 
-                                       (int64_t) s.st_mtime);
-                       /* And send it to the header handler */
-                       fetch_send_callback(FETCH_HEADER, f->fetch_handle, 
-                                       header, strlen(header),
-                                       FETCH_ERROR_NO_ERROR);
-
-                       /* create Content-Type */
-                       type = fetch_filetype(url_path);
-                       snprintf(header, sizeof header, 
-                                       "Content-Type: %s", type);
-                       /* Send it to the header handler */
-                       fetch_send_callback(FETCH_HEADER, f->fetch_handle,
-                                       header, strlen(header),
-                                       FETCH_ERROR_NO_ERROR);
-
-                       /* create Content-Length */
-                       snprintf(header, sizeof header, 
-                                       "Content-Length: %" PRId64, 
-                                       (int64_t) s.st_size);
-                       /* Send it to the header handler */
-                       fetch_send_callback(FETCH_HEADER, f->fetch_handle,
-                                       header, strlen(header),
-                                       FETCH_ERROR_NO_ERROR);
-
-                       /* don't set last modified time so as to ensure that 
-                        * local files are revalidated at all times. */
-
-                       /* Report not modified, if appropriate */
-                       if (f->last_modified && f->file_etag &&
-                                       f->last_modified > s.st_mtime &&
-                                       f->file_etag == s.st_mtime) {
-                               fetch_send_callback(FETCH_NOTMODIFIED, 
-                                               f->fetch_handle, 0, 0,
-                                               FETCH_ERROR_NO_ERROR);
-                               free(url_path);
-                               return true;
-                       }
-               }
-
-               if (url_path != NULL)
-                       free(url_path);
-       }
-
        if (f->abort)
                return true;
 
Index: content/fetch.c
===================================================================
--- content/fetch.c     (revision 10746)
+++ content/fetch.c     (working copy)
@@ -38,6 +38,7 @@
 #include "content/fetch.h"
 #include "content/fetchers/fetch_curl.h"
 #include "content/fetchers/fetch_data.h"
+#include "content/fetchers/fetch_file.h"
 #include "content/urldb.h"
 #include "desktop/netsurf.h"
 #include "desktop/options.h"
@@ -106,6 +107,7 @@
 {
        fetch_curl_register();
        fetch_data_register();
+       fetch_file_register();
        fetch_active = false;
 }
 
Index: amiga/filetype.c
===================================================================
--- amiga/filetype.c    (revision 10746)
+++ amiga/filetype.c    (working copy)
@@ -186,11 +186,6 @@
                        return "rosprite";
                break;
 #endif
-
-               case CONTENT_DIRECTORY:
-                       return "drawer";
-               break;
-
 #if defined(WITH_NS_SVG) || defined(WITH_RSVG)
                case CONTENT_SVG:
                        return "svg";


Conflicted files




Removed files


render/directory.c
render/directory.h

Reply via email to