Gitweb links:
...log
http://git.netsurf-browser.org/netsurf.git/shortlog/0908925ca67652e4e335c5f8ef4139ca6f60904f
...commit
http://git.netsurf-browser.org/netsurf.git/commit/0908925ca67652e4e335c5f8ef4139ca6f60904f
...tree
http://git.netsurf-browser.org/netsurf.git/tree/0908925ca67652e4e335c5f8ef4139ca6f60904f
The branch, master has been updated
via 0908925ca67652e4e335c5f8ef4139ca6f60904f (commit)
from 1697118e227406764d1cfad78a5fcc9febe152be (commit)
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=0908925ca67652e4e335c5f8ef4139ca6f60904f
commit 0908925ca67652e4e335c5f8ef4139ca6f60904f
Author: Vincent Sanders <[email protected]>
Commit: Vincent Sanders <[email protected]>
move the file fetcher sources into a single directory
diff --git a/content/Makefile b/content/Makefile
index abc5a24..188d0f4 100644
--- a/content/Makefile
+++ b/content/Makefile
@@ -3,7 +3,6 @@
S_CONTENT := \
content.c \
content_factory.c \
- dirlist.c \
fetch.c \
hlcache.c \
llcache.c \
@@ -18,10 +17,12 @@ ifeq ($(NETSURF_FS_BACKING_STORE),YES)
endif
-# Content fetchers sources
+# Content fetcher sources
include content/fetchers/Makefile
-# Content handlers
+S_FETCHERS := $(addprefix content/,$(S_FETCHERS))
+
+# Content handler sources
include content/handlers/Makefile
S_CONTENT := $(addprefix content/,$(S_CONTENT))
diff --git a/content/dirlist.c b/content/dirlist.c
deleted file mode 100644
index 3f79e65..0000000
--- a/content/dirlist.c
+++ /dev/null
@@ -1,406 +0,0 @@
-/*
- * Copyright 2010 Michael Drake <[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/>.
- */
-
-/** \file
- * Generate HTML content for displaying directory listings (implementation).
- */
-
-#include <stdbool.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "utils/nsurl.h"
-#include "utils/messages.h"
-#include "utils/nscolour.h"
-
-#include "netsurf/types.h"
-#include "netsurf/plot_style.h"
-
-#include "content/dirlist.h"
-#include "desktop/system_colour.h"
-
-static int dirlist_filesize_calculate(unsigned long *bytesize);
-static int dirlist_filesize_value(unsigned long bytesize);
-static char* dirlist_filesize_unit(unsigned long bytesize);
-
-
-/**
- * Generates the top part of an HTML directory listing page
- *
- * \return Top of directory listing HTML
- *
- * This is part of a series of functions. To generate a complete page,
- * call the following functions in order:
- *
- * dirlist_generate_top()
- * dirlist_generate_hide_columns() -- optional
- * dirlist_generate_title()
- * dirlist_generate_parent_link() -- optional
- * dirlist_generate_headings()
- * dirlist_generate_row() -- call 'n' times for 'n' rows
- * dirlist_generate_bottom()
- */
-
-bool dirlist_generate_top(char *buffer, int buffer_length)
-{
- int error = snprintf(buffer, buffer_length,
- "<html>\n"
- "<head>\n"
- "<link rel=\"stylesheet\" title=\"Standard\" "
- "type=\"text/css\" href=\"resource:internal.css\">\n"
- "<style>\n");
- if (error < 0 || error >= buffer_length)
- /* Error or buffer too small */
- return false;
- else
- /* OK */
- return true;
-
-}
-
-
-/**
- * Generates the part of an HTML directory listing page that can suppress
- * particular columns
- *
- * \param flags flags for which cols to suppress. 0 to suppress none
- * \param buffer buffer to fill with generated HTML
- * \param buffer_length maximum size of buffer
- * \return true iff buffer filled without error
- *
- * This is part of a series of functions. To generate a complete page,
- * call the following functions in order:
- *
- * dirlist_generate_top()
- * dirlist_generate_hide_columns() -- optional
- * dirlist_generate_title()
- * dirlist_generate_parent_link() -- optional
- * dirlist_generate_headings()
- * dirlist_generate_row() -- call 'n' times for 'n' rows
- * dirlist_generate_bottom()
- */
-
-bool dirlist_generate_hide_columns(int flags, char *buffer, int buffer_length)
-{
- int error = snprintf(buffer, buffer_length,
- "%s\n%s\n%s\n%s\n%s\n",
- (flags & DIRLIST_NO_NAME_COLUMN) ?
- "span.name { display: none; }\n" : "",
- (flags & DIRLIST_NO_TYPE_COLUMN) ?
- "span.type { display: none; }\n" : "",
- (flags & DIRLIST_NO_SIZE_COLUMN) ?
- "span.size { display: none; }\n" : "",
- (flags & DIRLIST_NO_DATE_COLUMN) ?
- "span.date { display: none; }\n" : "",
- (flags & DIRLIST_NO_TIME_COLUMN) ?
- "span.time { display: none; }\n" : "");
- if (error < 0 || error >= buffer_length)
- /* Error or buffer too small */
- return false;
- else
- /* OK */
- return true;
-}
-
-
-/**
- * Generates the part of an HTML directory listing page that contains the title
- *
- * \param title title to use
- * \param buffer buffer to fill with generated HTML
- * \param buffer_length maximum size of buffer
- * \return true iff buffer filled without error
- *
- * This is part of a series of functions. To generate a complete page,
- * call the following functions in order:
- *
- * dirlist_generate_top()
- * dirlist_generate_hide_columns() -- optional
- * dirlist_generate_title()
- * dirlist_generate_parent_link() -- optional
- * dirlist_generate_headings()
- * dirlist_generate_row() -- call 'n' times for 'n' rows
- * dirlist_generate_bottom()
- */
-
-bool dirlist_generate_title(const char *title, char *buffer, int buffer_length)
-{
- const char *stylesheet;
- nserror err;
- int error;
-
- if (title == NULL)
- title = "";
-
- err = nscolour_get_stylesheet(&stylesheet);
- if (err != NSERROR_OK) {
- return false;
- }
-
- error = snprintf(buffer, buffer_length,
- "</style>\n"
- "<title>%s</title>\n"
- "<style>\n"
- "html {\n"
- "\tbackground-color: #%06x;\n"
- "}\n"
- "%s"
- "</style>\n"
- "</head>\n"
- "<body id=\"dirlist\" class=\"ns-even-bg ns-even-fg
ns-border\">\n"
- "<h1 class=\"ns-border\">%s</h1>\n",
- title,
- colour_rb_swap(nscolours[NSCOLOUR_WIN_ODD_BG]),
- stylesheet, title);
- if (error < 0 || error >= buffer_length)
- /* Error or buffer too small */
- return false;
- else
- /* OK */
- return true;
-}
-
-
-/**
- * Generates the part of an HTML directory listing page that links to the
parent
- * directory
- *
- * \param parent url of parent directory
- * \param buffer buffer to fill with generated HTML
- * \param buffer_length maximum size of buffer
- * \return true iff buffer filled without error
- *
- * This is part of a series of functions. To generate a complete page,
- * call the following functions in order:
- *
- * dirlist_generate_top()
- * dirlist_generate_hide_columns() -- optional
- * dirlist_generate_title()
- * dirlist_generate_parent_link() -- optional
- * dirlist_generate_headings()
- * dirlist_generate_row() -- call 'n' times for 'n' rows
- * dirlist_generate_bottom()
- */
-
-bool dirlist_generate_parent_link(const char *parent, char *buffer,
- int buffer_length)
-{
- int error = snprintf(buffer, buffer_length,
- "<p><a href=\"%s\">%s</a></p>",
- parent, messages_get("FileParent"));
- if (error < 0 || error >= buffer_length)
- /* Error or buffer too small */
- return false;
- else
- /* OK */
- return true;
-}
-
-
-/**
- * Generates the part of an HTML directory listing page that displays the
column
- * headings
- *
- * \param buffer buffer to fill with generated HTML
- * \param buffer_length maximum size of buffer
- * \return true iff buffer filled without error
- *
- * This is part of a series of functions. To generate a complete page,
- * call the following functions in order:
- *
- * dirlist_generate_top()
- * dirlist_generate_hide_columns() -- optional
- * dirlist_generate_title()
- * dirlist_generate_parent_link() -- optional
- * dirlist_generate_headings()
- * dirlist_generate_row() -- call 'n' times for 'n' rows
- * dirlist_generate_bottom()
- */
-
-bool dirlist_generate_headings(char *buffer, int buffer_length)
-{
- int error = snprintf(buffer, buffer_length,
- "<div>\n"
- "<strong>\n"
- "\t<span class=\"name\">%s</span>\n"
- "\t<span class=\"type\">%s</span>\n"
- "\t<span class=\"size\">%s</span>"
- "<span class=\"size\"></span>\n"
- "\t<span class=\"date\">%s</span>\n"
- "\t<span class=\"time\">%s</span>\n"
- "</strong>\n",
- messages_get("FileName"), messages_get("FileType"),
- messages_get("FileSize"), messages_get("FileDate"),
- messages_get("FileTime"));
- if (error < 0 || error >= buffer_length)
- /* Error or buffer too small */
- return false;
- else
- /* OK */
- return true;
-}
-
-
-/**
- * Generates the part of an HTML directory listing page that displays a row
- * in the directory contents table
- *
- * \param even evenness of row number, for alternate row
colouring
- * \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 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
- * \param buffer buffer to fill with generated HTML
- * \param buffer_length maximum size of buffer
- * \return true iff buffer filled without error
- *
- * This is part of a series of functions. To generate a complete page,
- * call the following functions in order:
- *
- * dirlist_generate_top()
- * dirlist_generate_hide_columns() -- optional
- * dirlist_generate_title()
- * dirlist_generate_parent_link() -- optional
- * dirlist_generate_headings()
- * dirlist_generate_row() -- call 'n' times for 'n' rows
- * dirlist_generate_bottom()
- */
-
-bool dirlist_generate_row(bool even, bool directory, nsurl *url, char *name,
- const char *mimetype, long long size, char *date, char *time,
- char *buffer, int buffer_length)
-{
- const char *unit;
- char size_string[100];
- int error;
-
- if (size < 0) {
- unit = "";
- strncpy(size_string, "", sizeof size_string);
- } else {
- unit = messages_get(dirlist_filesize_unit((unsigned long)size));
- snprintf(size_string, sizeof size_string, "%d",
- dirlist_filesize_value((unsigned long)size));
- }
-
- error = snprintf(buffer, buffer_length,
- "<a href=\"%s\" class=\"%s %s\">\n"
- "\t<span class=\"name ns-border\">%s</span>\n"
- "\t<span class=\"type ns-border\">%s</span>\n"
- "\t<span class=\"size ns-border\">%s</span>"
- "<span class=\"size ns-border\">%s</span>\n"
- "\t<span class=\"date ns-border\">%s</span>\n"
- "\t<span class=\"time ns-border\">%s</span>\n"
- "</a>\n", nsurl_access(url),
- even ? "even ns-even-bg" : "odd ns-odd-bg",
- directory ? "dir" : "file",
- name, mimetype, size_string, unit, date, time);
- if (error < 0 || error >= buffer_length)
- /* Error or buffer too small */
- return false;
- else
- /* OK */
- return true;
-}
-
-
-/**
- * Generates the bottom part of an HTML directory listing page
- *
- * \return Bottom of directory listing HTML
- *
- * This is part of a series of functions. To generate a complete page,
- * call the following functions in order:
- *
- * dirlist_generate_top()
- * dirlist_generate_hide_columns() -- optional
- * dirlist_generate_title()
- * dirlist_generate_parent_link() -- optional
- * dirlist_generate_headings()
- * dirlist_generate_row() -- call 'n' times for 'n' rows
- * dirlist_generate_bottom()
- */
-
-bool dirlist_generate_bottom(char *buffer, int buffer_length)
-{
- 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;
-}
-
-
-/**
- * Obtain display value and units for filesize after conversion to B/kB/MB/GB,
- * as appropriate.
- *
- * \param bytesize file size in bytes, updated to filesize in output units
- * \return number of times bytesize has been divided by 1024
- */
-
-int dirlist_filesize_calculate(unsigned long *bytesize)
-{
- int i = 0;
- while (*bytesize > 1024 * 4) {
- *bytesize /= 1024;
- i++;
- if (i == 3)
- break;
- }
- return i;
-}
-
-
-/**
- * Obtain display value for filesize after conversion to B/kB/MB/GB,
- * as appropriate
- *
- * \param bytesize file size in bytes
- * \return Value to display for file size, in units given by filesize_unit()
- */
-
-int dirlist_filesize_value(unsigned long bytesize)
-{
- dirlist_filesize_calculate(&bytesize);
- return (int)bytesize;
-}
-
-
-/**
- * Obtain display units for filesize after conversion to B/kB/MB/GB,
- * as appropriate
- *
- * \param bytesize file size in bytes
- * \return Units to display for file size, for value given by filesize_value()
- */
-
-char* dirlist_filesize_unit(unsigned long bytesize)
-{
- const char* units[] = { "Bytes", "kBytes", "MBytes", "GBytes" };
- return (char*)units[dirlist_filesize_calculate(&bytesize)];
-}
diff --git a/content/dirlist.h b/content/dirlist.h
deleted file mode 100644
index 5cdaf75..0000000
--- a/content/dirlist.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2010 Michael Drake <[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/>.
- */
-
-/** \file
- * Generate HTML content for displaying directory listings (interface).
- *
- * These functions should in general be called via the content interface.
- */
-
-#ifndef _NETSURF_CONTENT_DIRLIST_H_
-#define _NETSURF_CONTENT_DIRLIST_H_
-
-#include <stdbool.h>
-
-#define DIRLIST_NO_NAME_COLUMN 1
-#define DIRLIST_NO_TYPE_COLUMN 1 << 1
-#define DIRLIST_NO_SIZE_COLUMN 1 << 2
-#define DIRLIST_NO_DATE_COLUMN 1 << 3
-#define DIRLIST_NO_TIME_COLUMN 1 << 4
-
-struct nsurl;
-
-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(const char *title, char *buffer, int
buffer_length);
-bool dirlist_generate_parent_link(const char *parent, char *buffer,
- int buffer_length);
-bool dirlist_generate_headings(char *buffer, int buffer_length);
-bool dirlist_generate_row(bool even, bool directory, struct nsurl *url,
- char *name, const char *mimetype, long long size, char *date,
- char *time, char *buffer, int buffer_length);
-bool dirlist_generate_bottom(char *buffer, int buffer_length);
-
-#endif
diff --git a/content/fetch.c b/content/fetch.c
index 4cc7859..a260799 100644
--- a/content/fetch.c
+++ b/content/fetch.c
@@ -56,7 +56,7 @@
#include "content/fetchers/about.h"
#include "content/fetchers/curl.h"
#include "content/fetchers/data.h"
-#include "content/fetchers/file.h"
+#include "content/fetchers/file/file.h"
#include "javascript/fetcher.h"
#include "content/urldb.h"
diff --git a/content/fetchers/Makefile b/content/fetchers/Makefile
index 9c84793..e87a4e8 100644
--- a/content/fetchers/Makefile
+++ b/content/fetchers/Makefile
@@ -1,10 +1,15 @@
# Content fetchers sources
-S_FETCHERS_YES := data.c file.c about.c resource.c
+S_FETCHERS_YES := data.c about.c resource.c
S_FETCHERS_NO :=
S_FETCHERS_$(NETSURF_USE_CURL) += curl.c
-S_FETCHERS := $(addprefix content/fetchers/,$(S_FETCHERS_YES))
+S_FETCHERS := $(addprefix fetchers/,$(S_FETCHERS_YES))
+
+# File fetcher
+include content/fetchers/file/Makefile
+
+S_FETCHERS += $(addprefix fetchers/file/,$(S_FETCHER_FILE))
# The following files depend on the testament
content/fetchers/about.c: testament $(OBJROOT)/testament.h
diff --git a/content/fetchers/file.c b/content/fetchers/file.c
deleted file mode 100644
index bf2cc32..0000000
--- a/content/fetchers/file.c
+++ /dev/null
@@ -1,844 +0,0 @@
-/*
- * 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 scheme URL handling. Based on the data fetcher by Rob Kendrick
- *
- * output dates and directory ordering are affected by the current locale
- */
-
-#include "utils/config.h"
-
-#include <stdlib.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdbool.h>
-#include <string.h>
-#include <strings.h>
-#include <time.h>
-#include <stdio.h>
-#include <stdarg.h>
-#ifdef HAVE_MMAP
-#include <sys/mman.h>
-#endif
-#include <libwapcaplet/libwapcaplet.h>
-
-#include "netsurf/inttypes.h"
-#include "utils/nsurl.h"
-#include "utils/dirent.h"
-#include "utils/corestrings.h"
-#include "utils/messages.h"
-#include "utils/utils.h"
-#include "utils/log.h"
-#include "utils/time.h"
-#include "utils/ring.h"
-#include "utils/file.h"
-#include "netsurf/fetch.h"
-#include "desktop/gui_internal.h"
-
-#include "content/dirlist.h"
-#include "content/fetch.h"
-#include "content/fetchers.h"
-#include "content/fetchers/file.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 */
-
- nsurl *url; /**< The full url the fetch refers to */
- char *path; /**< The actual path to be used with open() */
-
- time_t file_etag; /**< Request etag for file (previous st.m_time) */
-};
-
-static struct fetch_file_context *ring = NULL;
-
-/** issue fetch callbacks with locking */
-static inline bool fetch_file_send_callback(const fetch_msg *msg,
- struct fetch_file_context *ctx)
-{
- ctx->locked = true;
- fetch_send_callback(msg, ctx->fetchh);
- ctx->locked = false;
-
- return ctx->aborted;
-}
-
-static bool fetch_file_send_header(struct fetch_file_context *ctx,
- const char *fmt, ...)
-{
- fetch_msg msg;
- char header[64];
- va_list ap;
- int len;
-
- va_start(ap, fmt);
- len = vsnprintf(header, sizeof header, fmt, ap);
- va_end(ap);
-
- if (len >= (int)sizeof(header) || len < 0) {
- return false;
- }
-
- msg.type = FETCH_HEADER;
- msg.data.header_or_data.buf = (const uint8_t *) header;
- msg.data.header_or_data.len = len;
-
- return fetch_file_send_callback(&msg, ctx);
-}
-
-/** callback to initialise the file fetcher. */
-static bool fetch_file_initialise(lwc_string *scheme)
-{
- return true;
-}
-
-/** callback to initialise the file fetcher. */
-static void fetch_file_finalise(lwc_string *scheme)
-{
-}
-
-static bool fetch_file_can_fetch(const nsurl *url)
-{
- return true;
-}
-
-/** callback to set up a file fetch context. */
-static void *
-fetch_file_setup(struct fetch *fetchh,
- nsurl *url,
- bool only_2xx,
- bool downgrade_tls,
- const char *post_urlenc,
- const struct fetch_multipart_data *post_multipart,
- const char **headers)
-{
- struct fetch_file_context *ctx;
- int i;
- nserror ret;
-
- ctx = calloc(1, sizeof(*ctx));
- if (ctx == NULL)
- return NULL;
-
- ret = guit->file->nsurl_to_path(url, &ctx->path);
- if (ret != NSERROR_OK) {
- free(ctx);
- return NULL;
- }
-
- ctx->url = nsurl_ref(url);
-
- /* Scan request headers looking for If-None-Match */
- for (i = 0; headers[i] != NULL; i++) {
- if (strncasecmp(headers[i], "If-None-Match:",
- SLEN("If-None-Match:")) != 0) {
- continue;
- }
-
- /* If-None-Match: "12345678" */
- const char *d = headers[i] + SLEN("If-None-Match:");
-
- /* Scan to first digit, if any */
- while (*d != '\0' && (*d < '0' || '9' < *d))
- d++;
-
- /* Convert to time_t */
- if (*d != '\0') {
- ret = nsc_snptimet(d, strlen(d), &ctx->file_etag);
- if (ret != NSERROR_OK) {
- NSLOG(fetch, WARNING,
- "Bad If-None-Match value");
- }
- }
- }
-
- ctx->fetchh = fetchh;
-
- RING_INSERT(ring, ctx);
-
- return ctx;
-}
-
-/** callback to free a file fetch */
-static void fetch_file_free(void *ctx)
-{
- struct fetch_file_context *c = ctx;
- nsurl_unref(c->url);
- free(c->path);
- free(ctx);
-}
-
-/** callback to start a file fetch */
-static bool fetch_file_start(void *ctx)
-{
- return true;
-}
-
-/** callback to abort a file fetch */
-static void fetch_file_abort(void *ctx)
-{
- struct fetch_file_context *c = 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;
-}
-
-static int fetch_file_errno_to_http_code(int error_no)
-{
- switch (error_no) {
- case ENAMETOOLONG:
- return 400;
- case EACCES:
- return 403;
- case ENOENT:
- return 404;
- default:
- break;
- }
-
- return 500;
-}
-
-static void fetch_file_process_error(struct fetch_file_context *ctx, int code)
-{
- fetch_msg msg;
- char buffer[1024];
- const char *title;
- char key[8];
-
- /* 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;
-
- snprintf(key, sizeof key, "HTTP%03d", code);
- title = messages_get(key);
-
- 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, nsurl_access(ctx->url));
-
- msg.type = FETCH_DATA;
- msg.data.header_or_data.buf = (const uint8_t *) buffer;
- msg.data.header_or_data.len = strlen(buffer);
- if (fetch_file_send_callback(&msg, ctx))
- goto fetch_file_process_error_aborted;
-
- msg.type = FETCH_FINISHED;
- fetch_file_send_callback(&msg, ctx);
-
-fetch_file_process_error_aborted:
- return;
-}
-
-
-/** Process object as a regular file */
-static void fetch_file_process_plain(struct fetch_file_context *ctx,
- struct stat *fdstat)
-{
-#ifdef HAVE_MMAP
- fetch_msg msg;
- char *buf = NULL;
- size_t buf_size;
-
- int fd; /**< The file descriptor of the object */
-
- /* Check if we can just return not modified */
- if (ctx->file_etag != 0 && ctx->file_etag == fdstat->st_mtime) {
- fetch_set_http_code(ctx->fetchh, 304);
- msg.type = FETCH_NOTMODIFIED;
- fetch_file_send_callback(&msg, ctx);
- return;
- }
-
- fd = open(ctx->path, O_RDONLY);
- if (fd < 0) {
- /* process errors as appropriate */
- fetch_file_process_error(ctx,
- fetch_file_errno_to_http_code(errno));
- return;
- }
-
- /* set buffer size */
- buf_size = fdstat->st_size;
-
- /* allocate the buffer storage */
- if (buf_size > 0) {
- buf = mmap(NULL, buf_size, PROT_READ, MAP_SHARED, fd, 0);
- if (buf == MAP_FAILED) {
- msg.type = FETCH_ERROR;
- msg.data.error = "Unable to map memory for file data
buffer";
- fetch_file_send_callback(&msg, ctx);
- close(fd);
- 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",
- guit->fetch->filetype(ctx->path))) {
- goto fetch_file_process_aborted;
- }
-
- /* content length */
- if (fetch_file_send_header(ctx, "Content-Length: %" PRIsizet,
- fdstat->st_size)) {
- goto fetch_file_process_aborted;
- }
-
- /* create etag */
- if (fetch_file_send_header(ctx, "ETag: \"%10" PRId64 "\"",
- (int64_t) fdstat->st_mtime)) {
- goto fetch_file_process_aborted;
- }
-
- msg.type = FETCH_DATA;
- msg.data.header_or_data.buf = (const uint8_t *) buf;
- msg.data.header_or_data.len = buf_size;
- fetch_file_send_callback(&msg, ctx);
-
- if (ctx->aborted == false) {
- msg.type = FETCH_FINISHED;
- fetch_file_send_callback(&msg, ctx);
- }
-
-fetch_file_process_aborted:
-
- if (buf != NULL)
- munmap(buf, buf_size);
- close(fd);
-#else
- fetch_msg msg;
- char *buf;
- size_t buf_size;
-
- ssize_t tot_read = 0;
- ssize_t res;
-
- FILE *infile;
-
- /* Check if we can just return not modified */
- if (ctx->file_etag != 0 && ctx->file_etag == fdstat->st_mtime) {
- fetch_set_http_code(ctx->fetchh, 304);
- msg.type = FETCH_NOTMODIFIED;
- fetch_file_send_callback(&msg, ctx);
- return;
- }
-
- infile = fopen(ctx->path, "rb");
- if (infile == NULL) {
- /* process errors as appropriate */
- fetch_file_process_error(ctx,
- fetch_file_errno_to_http_code(errno));
- return;
- }
-
- /* set buffer size */
- buf_size = fdstat->st_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) {
- msg.type = FETCH_ERROR;
- msg.data.error =
- "Unable to allocate memory for file data buffer";
- fetch_file_send_callback(&msg, ctx);
- fclose(infile);
- 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",
- guit->fetch->filetype(ctx->path))) {
- goto fetch_file_process_aborted;
- }
-
- /* content length */
- if (fetch_file_send_header(ctx, "Content-Length: %" PRIsizet,
- fdstat->st_size)) {
- goto fetch_file_process_aborted;
- }
-
- /* create etag */
- if (fetch_file_send_header(ctx, "ETag: \"%10" PRId64 "\"",
- (int64_t) fdstat->st_mtime)) {
- goto fetch_file_process_aborted;
- }
-
- /* main data loop */
- while (tot_read < fdstat->st_size) {
- res = fread(buf, 1, buf_size, infile);
- if (res == 0) {
- if (feof(infile)) {
- msg.type = FETCH_ERROR;
- msg.data.error = "Unexpected EOF reading file";
- fetch_file_send_callback(&msg, ctx);
- goto fetch_file_process_aborted;
- } else {
- msg.type = FETCH_ERROR;
- msg.data.error = "Error reading file";
- fetch_file_send_callback(&msg, ctx);
- goto fetch_file_process_aborted;
- }
- }
- tot_read += res;
-
- msg.type = FETCH_DATA;
- msg.data.header_or_data.buf = (const uint8_t *) buf;
- msg.data.header_or_data.len = res;
- if (fetch_file_send_callback(&msg, ctx))
- break;
- }
-
- if (ctx->aborted == false) {
- msg.type = FETCH_FINISHED;
- fetch_file_send_callback(&msg, ctx);
- }
-
-fetch_file_process_aborted:
-
- fclose(infile);
- free(buf);
-#endif
- 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) * SLEN("&") + 1);
- if (nice_path == NULL) {
- 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 if (*tmp == '&') {
- *cnv++ = '&';
- *cnv++ = 'a';
- *cnv++ = 'm';
- *cnv++ = 'p';
- *cnv++ = ';';
- } else {
- *cnv++ = *tmp;
- }
- }
- *cnv = '\0';
-
- /* Construct a localised title string */
- title_length = (cnv - nice_path) + strlen(messages_get("FileIndex"));
- title = malloc(title_length + 1);
-
- if (title == NULL) {
- free(nice_path);
- return NULL;
- }
-
- /* Set title to localised "Index of <nice_path>" */
- snprintf(title, title_length, messages_get("FileIndex"), nice_path);
-
- free(nice_path);
-
- return title;
-}
-
-/**
- * Generate an output row of the directory listing.
- *
- * \param ctx The file fetching context.
- * \param ent current directory entry.
- * \param even is the row an even row.
- * \param buffer The output buffer.
- * \param buffer_len The space available in the output buffer.
- * \return NSERROR_OK or error code on faliure.
- */
-static nserror
-process_dir_ent(struct fetch_file_context *ctx,
- struct dirent *ent,
- bool even,
- char *buffer,
- size_t buffer_len)
-{
- nserror ret;
- char *urlpath = NULL; /* buffer for leaf entry path */
- struct stat ent_stat; /* stat result of leaf entry */
- char datebuf[64]; /* buffer for date text */
- char timebuf[64]; /* buffer for time text */
- nsurl *url;
-
- /* skip hidden files */
- if (ent->d_name[0] == '.') {
- return NSERROR_BAD_PARAMETER;
- }
-
- ret = netsurf_mkpath(&urlpath, NULL, 2, ctx->path, ent->d_name);
- if (ret != NSERROR_OK) {
- return ret;
- }
-
- if (stat(urlpath, &ent_stat) != 0) {
- ent_stat.st_mode = 0;
- datebuf[0] = 0;
- timebuf[0] = 0;
- } else {
- /* Get date in output format. a (day of week) and b
- * (month) are both affected by the locale
- */
- if (strftime((char *)&datebuf, sizeof datebuf, "%a %d %b %Y",
- localtime(&ent_stat.st_mtime)) == 0) {
- datebuf[0] = '-';
- datebuf[1] = 0;
- }
-
- /* Get time in output format */
- if (strftime((char *)&timebuf, sizeof timebuf, "%H:%M",
- localtime(&ent_stat.st_mtime)) == 0) {
- timebuf[0] = '-';
- timebuf[1] = 0;
- }
- }
-
- ret = guit->file->path_to_nsurl(urlpath, &url);
- if (ret != NSERROR_OK) {
- free(urlpath);
- return ret;
- }
-
- if (S_ISREG(ent_stat.st_mode)) {
- /* regular file */
- dirlist_generate_row(even,
- false,
- url,
- ent->d_name,
- guit->fetch->filetype(urlpath),
- ent_stat.st_size,
- datebuf, timebuf,
- buffer, buffer_len);
- } else if (S_ISDIR(ent_stat.st_mode)) {
- /* directory */
- dirlist_generate_row(even,
- true,
- url,
- ent->d_name,
- messages_get("FileDirectory"),
- -1,
- datebuf, timebuf,
- buffer, buffer_len);
- } else {
- /* something else */
- dirlist_generate_row(even,
- false,
- url,
- ent->d_name,
- "",
- -1,
- datebuf, timebuf,
- buffer, buffer_len);
- }
-
- nsurl_unref(url);
- free(urlpath);
-
- return NSERROR_OK;
-}
-
-/**
- * Comparison function for sorting directories.
- *
- * Correctly orders non zero-padded numerical parts.
- * ie. produces "file1, file2, file10" rather than "file1, file10, file2".
- *
- * \param d1 first directory entry
- * \param d2 second directory entry
- */
-static int dir_sort_alpha(const struct dirent **d1, const struct dirent **d2)
-{
- const char *s1 = (*d1)->d_name;
- const char *s2 = (*d2)->d_name;
-
- while (*s1 != '\0' && *s2 != '\0') {
- if ((*s1 >= '0' && *s1 <= '9') &&
- (*s2 >= '0' && *s2 <= '9')) {
- int n1 = 0, n2 = 0;
- while (*s1 >= '0' && *s1 <= '9') {
- n1 = n1 * 10 + (*s1) - '0';
- s1++;
- }
- while (*s2 >= '0' && *s2 <= '9') {
- n2 = n2 * 10 + (*s2) - '0';
- s2++;
- }
- if (n1 != n2) {
- return n1 - n2;
- }
- if (*s1 == '\0' || *s2 == '\0')
- break;
- }
- if (tolower(*s1) != tolower(*s2))
- break;
-
- s1++;
- s2++;
- }
-
- return tolower(*s1) - tolower(*s2);
-}
-
-static void fetch_file_process_dir(struct fetch_file_context *ctx,
- struct stat *fdstat)
-{
- fetch_msg msg;
- char buffer[1024]; /* Output buffer */
- bool even = false; /* formatting flag */
- char *title; /* pretty printed title */
- nserror err; /* result from url routines */
- nsurl *up; /* url of parent */
-
- struct dirent **listing = NULL; /* directory entry listing */
- int i; /* directory entry index */
- int n; /* number of directory entries */
-
- n = scandir(ctx->path, &listing, 0, dir_sort_alpha);
- if (n < 0) {
- fetch_file_process_error(ctx,
- fetch_file_errno_to_http_code(errno));
- return;
- }
-
- /* fetch is going to be successful */
- fetch_set_http_code(ctx->fetchh, 200);
-
- /* force no-cache */
- if (fetch_file_send_header(ctx, "Cache-Control: no-cache"))
- goto fetch_file_process_dir_aborted;
-
- /* content type */
- if (fetch_file_send_header(ctx, "Content-Type: text/html"))
- goto fetch_file_process_dir_aborted;
-
- msg.type = FETCH_DATA;
- msg.data.header_or_data.buf = (const uint8_t *) buffer;
-
- /* directory listing top */
- dirlist_generate_top(buffer, sizeof buffer);
- msg.data.header_or_data.len = strlen(buffer);
- if (fetch_file_send_callback(&msg, ctx))
- goto fetch_file_process_dir_aborted;
-
- /* directory listing title */
- title = gen_nice_title(ctx->path);
- dirlist_generate_title(title, buffer, sizeof buffer);
- free(title);
- msg.data.header_or_data.len = strlen(buffer);
- if (fetch_file_send_callback(&msg, ctx))
- goto fetch_file_process_dir_aborted;
-
- /* Print parent directory link */
- err = nsurl_parent(ctx->url, &up);
- if (err == NSERROR_OK) {
- if (nsurl_compare(ctx->url, up, NSURL_COMPLETE) == false) {
- /* different URL; have parent */
- dirlist_generate_parent_link(nsurl_access(up),
- buffer, sizeof buffer);
-
- msg.data.header_or_data.len = strlen(buffer);
- fetch_file_send_callback(&msg, ctx);
- }
- nsurl_unref(up);
-
- if (ctx->aborted)
- goto fetch_file_process_dir_aborted;
-
- }
-
- /* directory list headings */
- dirlist_generate_headings(buffer, sizeof buffer);
- msg.data.header_or_data.len = strlen(buffer);
- if (fetch_file_send_callback(&msg, ctx))
- goto fetch_file_process_dir_aborted;
-
- for (i = 0; i < n; i++) {
-
- err = process_dir_ent(ctx, listing[i], even, buffer,
- sizeof(buffer));
-
- if (err == NSERROR_OK) {
- msg.data.header_or_data.len = strlen(buffer);
- if (fetch_file_send_callback(&msg, ctx))
- goto fetch_file_process_dir_aborted;
-
- even = !even;
- }
- }
-
- /* directory listing bottom */
- dirlist_generate_bottom(buffer, sizeof buffer);
- msg.data.header_or_data.len = strlen(buffer);
- if (fetch_file_send_callback(&msg, ctx))
- goto fetch_file_process_dir_aborted;
-
- msg.type = FETCH_FINISHED;
- fetch_file_send_callback(&msg, ctx);
-
-fetch_file_process_dir_aborted:
-
- if (listing != NULL) {
- for (i = 0; i < n; i++) {
- free(listing[i]);
- }
- free(listing);
- }
-}
-
-
-/* process a file fetch */
-static void fetch_file_process(struct fetch_file_context *ctx)
-{
- struct stat fdstat; /**< The objects stat */
-
- if (stat(ctx->path, &fdstat) != 0) {
- /* process errors as appropriate */
- fetch_file_process_error(ctx,
- fetch_file_errno_to_http_code(errno));
- return;
- }
-
- if (S_ISDIR(fdstat.st_mode)) {
- /* directory listing */
- fetch_file_process_dir(ctx, &fdstat);
- return;
- } else if (S_ISREG(fdstat.st_mode)) {
- /* regular file */
- fetch_file_process_plain(ctx, &fdstat);
- return;
- } else {
- /* unhandled type of file */
- fetch_file_process_error(ctx, 501);
- }
-
- return;
-}
-
-/** callback to poll for additional file fetch contents */
-static void fetch_file_poll(lwc_string *scheme)
-{
- struct fetch_file_context *c, *save_ring = NULL;
-
- while (ring != NULL) {
- /* Take the first entry from the ring */
- c = ring;
- RING_REMOVE(ring, c);
-
- /* 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) {
- RING_INSERT(save_ring, c);
- continue;
- }
-
- /* Only process non-aborted fetches */
- if (c->aborted == false) {
- /* file fetches can be processed in one go */
- fetch_file_process(c);
- }
-
- /* And now finish */
- fetch_remove_from_queues(c->fetchh);
- fetch_free(c->fetchh);
-
- }
-
- /* Finally, if we saved any fetches which were locked, put them back
- * into the ring for next time
- */
- ring = save_ring;
-}
-
-nserror fetch_file_register(void)
-{
- lwc_string *scheme = lwc_string_ref(corestring_lwc_file);
- const struct fetcher_operation_table fetcher_ops = {
- .initialise = fetch_file_initialise,
- .acceptable = fetch_file_can_fetch,
- .setup = fetch_file_setup,
- .start = fetch_file_start,
- .abort = fetch_file_abort,
- .free = fetch_file_free,
- .poll = fetch_file_poll,
- .finalise = fetch_file_finalise
- };
-
- return fetcher_add(scheme, &fetcher_ops);
-}
diff --git a/content/fetchers/file.h b/content/fetchers/file.h
deleted file mode 100644
index 5a5cfe8..0000000
--- a/content/fetchers/file.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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 scheme fetcher handler interface.
- */
-
-#ifndef NETSURF_CONTENT_FETCHERS_FETCH_FILE_H
-#define NETSURF_CONTENT_FETCHERS_FETCH_FILE_H
-
-/**
- * Register file scheme handler.
- *
- * \return NSERROR_OK on successful registration or error code on failure.
- */
-nserror fetch_file_register(void);
-
-#endif
diff --git a/content/fetchers/file/Makefile b/content/fetchers/file/Makefile
new file mode 100644
index 0000000..c22400a
--- /dev/null
+++ b/content/fetchers/file/Makefile
@@ -0,0 +1,3 @@
+# File fetcher sources
+
+S_FETCHER_FILE := dirlist.c file.c
diff --git a/content/fetchers/file/dirlist.c b/content/fetchers/file/dirlist.c
new file mode 100644
index 0000000..d49dc7f
--- /dev/null
+++ b/content/fetchers/file/dirlist.c
@@ -0,0 +1,406 @@
+/*
+ * Copyright 2010 Michael Drake <[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/>.
+ */
+
+/** \file
+ * Generate HTML content for displaying directory listings (implementation).
+ */
+
+#include <stdbool.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "utils/nsurl.h"
+#include "utils/messages.h"
+#include "utils/nscolour.h"
+
+#include "netsurf/types.h"
+#include "netsurf/plot_style.h"
+
+#include "dirlist.h"
+#include "desktop/system_colour.h"
+
+static int dirlist_filesize_calculate(unsigned long *bytesize);
+static int dirlist_filesize_value(unsigned long bytesize);
+static char* dirlist_filesize_unit(unsigned long bytesize);
+
+
+/**
+ * Generates the top part of an HTML directory listing page
+ *
+ * \return Top of directory listing HTML
+ *
+ * This is part of a series of functions. To generate a complete page,
+ * call the following functions in order:
+ *
+ * dirlist_generate_top()
+ * dirlist_generate_hide_columns() -- optional
+ * dirlist_generate_title()
+ * dirlist_generate_parent_link() -- optional
+ * dirlist_generate_headings()
+ * dirlist_generate_row() -- call 'n' times for 'n' rows
+ * dirlist_generate_bottom()
+ */
+
+bool dirlist_generate_top(char *buffer, int buffer_length)
+{
+ int error = snprintf(buffer, buffer_length,
+ "<html>\n"
+ "<head>\n"
+ "<link rel=\"stylesheet\" title=\"Standard\" "
+ "type=\"text/css\" href=\"resource:internal.css\">\n"
+ "<style>\n");
+ if (error < 0 || error >= buffer_length)
+ /* Error or buffer too small */
+ return false;
+ else
+ /* OK */
+ return true;
+
+}
+
+
+/**
+ * Generates the part of an HTML directory listing page that can suppress
+ * particular columns
+ *
+ * \param flags flags for which cols to suppress. 0 to suppress none
+ * \param buffer buffer to fill with generated HTML
+ * \param buffer_length maximum size of buffer
+ * \return true iff buffer filled without error
+ *
+ * This is part of a series of functions. To generate a complete page,
+ * call the following functions in order:
+ *
+ * dirlist_generate_top()
+ * dirlist_generate_hide_columns() -- optional
+ * dirlist_generate_title()
+ * dirlist_generate_parent_link() -- optional
+ * dirlist_generate_headings()
+ * dirlist_generate_row() -- call 'n' times for 'n' rows
+ * dirlist_generate_bottom()
+ */
+
+bool dirlist_generate_hide_columns(int flags, char *buffer, int buffer_length)
+{
+ int error = snprintf(buffer, buffer_length,
+ "%s\n%s\n%s\n%s\n%s\n",
+ (flags & DIRLIST_NO_NAME_COLUMN) ?
+ "span.name { display: none; }\n" : "",
+ (flags & DIRLIST_NO_TYPE_COLUMN) ?
+ "span.type { display: none; }\n" : "",
+ (flags & DIRLIST_NO_SIZE_COLUMN) ?
+ "span.size { display: none; }\n" : "",
+ (flags & DIRLIST_NO_DATE_COLUMN) ?
+ "span.date { display: none; }\n" : "",
+ (flags & DIRLIST_NO_TIME_COLUMN) ?
+ "span.time { display: none; }\n" : "");
+ if (error < 0 || error >= buffer_length)
+ /* Error or buffer too small */
+ return false;
+ else
+ /* OK */
+ return true;
+}
+
+
+/**
+ * Generates the part of an HTML directory listing page that contains the title
+ *
+ * \param title title to use
+ * \param buffer buffer to fill with generated HTML
+ * \param buffer_length maximum size of buffer
+ * \return true iff buffer filled without error
+ *
+ * This is part of a series of functions. To generate a complete page,
+ * call the following functions in order:
+ *
+ * dirlist_generate_top()
+ * dirlist_generate_hide_columns() -- optional
+ * dirlist_generate_title()
+ * dirlist_generate_parent_link() -- optional
+ * dirlist_generate_headings()
+ * dirlist_generate_row() -- call 'n' times for 'n' rows
+ * dirlist_generate_bottom()
+ */
+
+bool dirlist_generate_title(const char *title, char *buffer, int buffer_length)
+{
+ const char *stylesheet;
+ nserror err;
+ int error;
+
+ if (title == NULL)
+ title = "";
+
+ err = nscolour_get_stylesheet(&stylesheet);
+ if (err != NSERROR_OK) {
+ return false;
+ }
+
+ error = snprintf(buffer, buffer_length,
+ "</style>\n"
+ "<title>%s</title>\n"
+ "<style>\n"
+ "html {\n"
+ "\tbackground-color: #%06x;\n"
+ "}\n"
+ "%s"
+ "</style>\n"
+ "</head>\n"
+ "<body id=\"dirlist\" class=\"ns-even-bg ns-even-fg
ns-border\">\n"
+ "<h1 class=\"ns-border\">%s</h1>\n",
+ title,
+ colour_rb_swap(nscolours[NSCOLOUR_WIN_ODD_BG]),
+ stylesheet, title);
+ if (error < 0 || error >= buffer_length)
+ /* Error or buffer too small */
+ return false;
+ else
+ /* OK */
+ return true;
+}
+
+
+/**
+ * Generates the part of an HTML directory listing page that links to the
parent
+ * directory
+ *
+ * \param parent url of parent directory
+ * \param buffer buffer to fill with generated HTML
+ * \param buffer_length maximum size of buffer
+ * \return true iff buffer filled without error
+ *
+ * This is part of a series of functions. To generate a complete page,
+ * call the following functions in order:
+ *
+ * dirlist_generate_top()
+ * dirlist_generate_hide_columns() -- optional
+ * dirlist_generate_title()
+ * dirlist_generate_parent_link() -- optional
+ * dirlist_generate_headings()
+ * dirlist_generate_row() -- call 'n' times for 'n' rows
+ * dirlist_generate_bottom()
+ */
+
+bool dirlist_generate_parent_link(const char *parent, char *buffer,
+ int buffer_length)
+{
+ int error = snprintf(buffer, buffer_length,
+ "<p><a href=\"%s\">%s</a></p>",
+ parent, messages_get("FileParent"));
+ if (error < 0 || error >= buffer_length)
+ /* Error or buffer too small */
+ return false;
+ else
+ /* OK */
+ return true;
+}
+
+
+/**
+ * Generates the part of an HTML directory listing page that displays the
column
+ * headings
+ *
+ * \param buffer buffer to fill with generated HTML
+ * \param buffer_length maximum size of buffer
+ * \return true iff buffer filled without error
+ *
+ * This is part of a series of functions. To generate a complete page,
+ * call the following functions in order:
+ *
+ * dirlist_generate_top()
+ * dirlist_generate_hide_columns() -- optional
+ * dirlist_generate_title()
+ * dirlist_generate_parent_link() -- optional
+ * dirlist_generate_headings()
+ * dirlist_generate_row() -- call 'n' times for 'n' rows
+ * dirlist_generate_bottom()
+ */
+
+bool dirlist_generate_headings(char *buffer, int buffer_length)
+{
+ int error = snprintf(buffer, buffer_length,
+ "<div>\n"
+ "<strong>\n"
+ "\t<span class=\"name\">%s</span>\n"
+ "\t<span class=\"type\">%s</span>\n"
+ "\t<span class=\"size\">%s</span>"
+ "<span class=\"size\"></span>\n"
+ "\t<span class=\"date\">%s</span>\n"
+ "\t<span class=\"time\">%s</span>\n"
+ "</strong>\n",
+ messages_get("FileName"), messages_get("FileType"),
+ messages_get("FileSize"), messages_get("FileDate"),
+ messages_get("FileTime"));
+ if (error < 0 || error >= buffer_length)
+ /* Error or buffer too small */
+ return false;
+ else
+ /* OK */
+ return true;
+}
+
+
+/**
+ * Generates the part of an HTML directory listing page that displays a row
+ * in the directory contents table
+ *
+ * \param even evenness of row number, for alternate row
colouring
+ * \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 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
+ * \param buffer buffer to fill with generated HTML
+ * \param buffer_length maximum size of buffer
+ * \return true iff buffer filled without error
+ *
+ * This is part of a series of functions. To generate a complete page,
+ * call the following functions in order:
+ *
+ * dirlist_generate_top()
+ * dirlist_generate_hide_columns() -- optional
+ * dirlist_generate_title()
+ * dirlist_generate_parent_link() -- optional
+ * dirlist_generate_headings()
+ * dirlist_generate_row() -- call 'n' times for 'n' rows
+ * dirlist_generate_bottom()
+ */
+
+bool dirlist_generate_row(bool even, bool directory, nsurl *url, char *name,
+ const char *mimetype, long long size, char *date, char *time,
+ char *buffer, int buffer_length)
+{
+ const char *unit;
+ char size_string[100];
+ int error;
+
+ if (size < 0) {
+ unit = "";
+ strncpy(size_string, "", sizeof size_string);
+ } else {
+ unit = messages_get(dirlist_filesize_unit((unsigned long)size));
+ snprintf(size_string, sizeof size_string, "%d",
+ dirlist_filesize_value((unsigned long)size));
+ }
+
+ error = snprintf(buffer, buffer_length,
+ "<a href=\"%s\" class=\"%s %s\">\n"
+ "\t<span class=\"name ns-border\">%s</span>\n"
+ "\t<span class=\"type ns-border\">%s</span>\n"
+ "\t<span class=\"size ns-border\">%s</span>"
+ "<span class=\"size ns-border\">%s</span>\n"
+ "\t<span class=\"date ns-border\">%s</span>\n"
+ "\t<span class=\"time ns-border\">%s</span>\n"
+ "</a>\n", nsurl_access(url),
+ even ? "even ns-even-bg" : "odd ns-odd-bg",
+ directory ? "dir" : "file",
+ name, mimetype, size_string, unit, date, time);
+ if (error < 0 || error >= buffer_length)
+ /* Error or buffer too small */
+ return false;
+ else
+ /* OK */
+ return true;
+}
+
+
+/**
+ * Generates the bottom part of an HTML directory listing page
+ *
+ * \return Bottom of directory listing HTML
+ *
+ * This is part of a series of functions. To generate a complete page,
+ * call the following functions in order:
+ *
+ * dirlist_generate_top()
+ * dirlist_generate_hide_columns() -- optional
+ * dirlist_generate_title()
+ * dirlist_generate_parent_link() -- optional
+ * dirlist_generate_headings()
+ * dirlist_generate_row() -- call 'n' times for 'n' rows
+ * dirlist_generate_bottom()
+ */
+
+bool dirlist_generate_bottom(char *buffer, int buffer_length)
+{
+ 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;
+}
+
+
+/**
+ * Obtain display value and units for filesize after conversion to B/kB/MB/GB,
+ * as appropriate.
+ *
+ * \param bytesize file size in bytes, updated to filesize in output units
+ * \return number of times bytesize has been divided by 1024
+ */
+
+int dirlist_filesize_calculate(unsigned long *bytesize)
+{
+ int i = 0;
+ while (*bytesize > 1024 * 4) {
+ *bytesize /= 1024;
+ i++;
+ if (i == 3)
+ break;
+ }
+ return i;
+}
+
+
+/**
+ * Obtain display value for filesize after conversion to B/kB/MB/GB,
+ * as appropriate
+ *
+ * \param bytesize file size in bytes
+ * \return Value to display for file size, in units given by filesize_unit()
+ */
+
+int dirlist_filesize_value(unsigned long bytesize)
+{
+ dirlist_filesize_calculate(&bytesize);
+ return (int)bytesize;
+}
+
+
+/**
+ * Obtain display units for filesize after conversion to B/kB/MB/GB,
+ * as appropriate
+ *
+ * \param bytesize file size in bytes
+ * \return Units to display for file size, for value given by filesize_value()
+ */
+
+char* dirlist_filesize_unit(unsigned long bytesize)
+{
+ const char* units[] = { "Bytes", "kBytes", "MBytes", "GBytes" };
+ return (char*)units[dirlist_filesize_calculate(&bytesize)];
+}
diff --git a/content/fetchers/file/dirlist.h b/content/fetchers/file/dirlist.h
new file mode 100644
index 0000000..3a0d48c
--- /dev/null
+++ b/content/fetchers/file/dirlist.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2010 Michael Drake <[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/>.
+ */
+
+/**
+ * \file
+ * interface to generate HTML content for displaying directory listings.
+ *
+ * These functions should in general be called via the content interface.
+ */
+
+#ifndef NETSURF_CONTENT_DIRLIST_H_
+#define NETSURF_CONTENT_DIRLIST_H_
+
+#include <stdbool.h>
+
+#define DIRLIST_NO_NAME_COLUMN 1
+#define DIRLIST_NO_TYPE_COLUMN 1 << 1
+#define DIRLIST_NO_SIZE_COLUMN 1 << 2
+#define DIRLIST_NO_DATE_COLUMN 1 << 3
+#define DIRLIST_NO_TIME_COLUMN 1 << 4
+
+struct nsurl;
+
+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(const char *title, char *buffer, int
buffer_length);
+bool dirlist_generate_parent_link(const char *parent, char *buffer,
+ int buffer_length);
+bool dirlist_generate_headings(char *buffer, int buffer_length);
+bool dirlist_generate_row(bool even, bool directory, struct nsurl *url,
+ char *name, const char *mimetype, long long size, char *date,
+ char *time, char *buffer, int buffer_length);
+bool dirlist_generate_bottom(char *buffer, int buffer_length);
+
+#endif
diff --git a/content/fetchers/file/file.c b/content/fetchers/file/file.c
new file mode 100644
index 0000000..ff3a1b1
--- /dev/null
+++ b/content/fetchers/file/file.c
@@ -0,0 +1,844 @@
+/*
+ * 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 scheme URL handling. Based on the data fetcher by Rob Kendrick
+ *
+ * output dates and directory ordering are affected by the current locale
+ */
+
+#include "utils/config.h"
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <string.h>
+#include <strings.h>
+#include <time.h>
+#include <stdio.h>
+#include <stdarg.h>
+#ifdef HAVE_MMAP
+#include <sys/mman.h>
+#endif
+#include <libwapcaplet/libwapcaplet.h>
+
+#include "netsurf/inttypes.h"
+#include "utils/nsurl.h"
+#include "utils/dirent.h"
+#include "utils/corestrings.h"
+#include "utils/messages.h"
+#include "utils/utils.h"
+#include "utils/log.h"
+#include "utils/time.h"
+#include "utils/ring.h"
+#include "utils/file.h"
+#include "netsurf/fetch.h"
+#include "desktop/gui_internal.h"
+
+#include "content/fetch.h"
+#include "content/fetchers.h"
+#include "dirlist.h"
+#include "file.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 */
+
+ nsurl *url; /**< The full url the fetch refers to */
+ char *path; /**< The actual path to be used with open() */
+
+ time_t file_etag; /**< Request etag for file (previous st.m_time) */
+};
+
+static struct fetch_file_context *ring = NULL;
+
+/** issue fetch callbacks with locking */
+static inline bool fetch_file_send_callback(const fetch_msg *msg,
+ struct fetch_file_context *ctx)
+{
+ ctx->locked = true;
+ fetch_send_callback(msg, ctx->fetchh);
+ ctx->locked = false;
+
+ return ctx->aborted;
+}
+
+static bool fetch_file_send_header(struct fetch_file_context *ctx,
+ const char *fmt, ...)
+{
+ fetch_msg msg;
+ char header[64];
+ va_list ap;
+ int len;
+
+ va_start(ap, fmt);
+ len = vsnprintf(header, sizeof header, fmt, ap);
+ va_end(ap);
+
+ if (len >= (int)sizeof(header) || len < 0) {
+ return false;
+ }
+
+ msg.type = FETCH_HEADER;
+ msg.data.header_or_data.buf = (const uint8_t *) header;
+ msg.data.header_or_data.len = len;
+
+ return fetch_file_send_callback(&msg, ctx);
+}
+
+/** callback to initialise the file fetcher. */
+static bool fetch_file_initialise(lwc_string *scheme)
+{
+ return true;
+}
+
+/** callback to initialise the file fetcher. */
+static void fetch_file_finalise(lwc_string *scheme)
+{
+}
+
+static bool fetch_file_can_fetch(const nsurl *url)
+{
+ return true;
+}
+
+/** callback to set up a file fetch context. */
+static void *
+fetch_file_setup(struct fetch *fetchh,
+ nsurl *url,
+ bool only_2xx,
+ bool downgrade_tls,
+ const char *post_urlenc,
+ const struct fetch_multipart_data *post_multipart,
+ const char **headers)
+{
+ struct fetch_file_context *ctx;
+ int i;
+ nserror ret;
+
+ ctx = calloc(1, sizeof(*ctx));
+ if (ctx == NULL)
+ return NULL;
+
+ ret = guit->file->nsurl_to_path(url, &ctx->path);
+ if (ret != NSERROR_OK) {
+ free(ctx);
+ return NULL;
+ }
+
+ ctx->url = nsurl_ref(url);
+
+ /* Scan request headers looking for If-None-Match */
+ for (i = 0; headers[i] != NULL; i++) {
+ if (strncasecmp(headers[i], "If-None-Match:",
+ SLEN("If-None-Match:")) != 0) {
+ continue;
+ }
+
+ /* If-None-Match: "12345678" */
+ const char *d = headers[i] + SLEN("If-None-Match:");
+
+ /* Scan to first digit, if any */
+ while (*d != '\0' && (*d < '0' || '9' < *d))
+ d++;
+
+ /* Convert to time_t */
+ if (*d != '\0') {
+ ret = nsc_snptimet(d, strlen(d), &ctx->file_etag);
+ if (ret != NSERROR_OK) {
+ NSLOG(fetch, WARNING,
+ "Bad If-None-Match value");
+ }
+ }
+ }
+
+ ctx->fetchh = fetchh;
+
+ RING_INSERT(ring, ctx);
+
+ return ctx;
+}
+
+/** callback to free a file fetch */
+static void fetch_file_free(void *ctx)
+{
+ struct fetch_file_context *c = ctx;
+ nsurl_unref(c->url);
+ free(c->path);
+ free(ctx);
+}
+
+/** callback to start a file fetch */
+static bool fetch_file_start(void *ctx)
+{
+ return true;
+}
+
+/** callback to abort a file fetch */
+static void fetch_file_abort(void *ctx)
+{
+ struct fetch_file_context *c = 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;
+}
+
+static int fetch_file_errno_to_http_code(int error_no)
+{
+ switch (error_no) {
+ case ENAMETOOLONG:
+ return 400;
+ case EACCES:
+ return 403;
+ case ENOENT:
+ return 404;
+ default:
+ break;
+ }
+
+ return 500;
+}
+
+static void fetch_file_process_error(struct fetch_file_context *ctx, int code)
+{
+ fetch_msg msg;
+ char buffer[1024];
+ const char *title;
+ char key[8];
+
+ /* 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;
+
+ snprintf(key, sizeof key, "HTTP%03d", code);
+ title = messages_get(key);
+
+ 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, nsurl_access(ctx->url));
+
+ msg.type = FETCH_DATA;
+ msg.data.header_or_data.buf = (const uint8_t *) buffer;
+ msg.data.header_or_data.len = strlen(buffer);
+ if (fetch_file_send_callback(&msg, ctx))
+ goto fetch_file_process_error_aborted;
+
+ msg.type = FETCH_FINISHED;
+ fetch_file_send_callback(&msg, ctx);
+
+fetch_file_process_error_aborted:
+ return;
+}
+
+
+/** Process object as a regular file */
+static void fetch_file_process_plain(struct fetch_file_context *ctx,
+ struct stat *fdstat)
+{
+#ifdef HAVE_MMAP
+ fetch_msg msg;
+ char *buf = NULL;
+ size_t buf_size;
+
+ int fd; /**< The file descriptor of the object */
+
+ /* Check if we can just return not modified */
+ if (ctx->file_etag != 0 && ctx->file_etag == fdstat->st_mtime) {
+ fetch_set_http_code(ctx->fetchh, 304);
+ msg.type = FETCH_NOTMODIFIED;
+ fetch_file_send_callback(&msg, ctx);
+ return;
+ }
+
+ fd = open(ctx->path, O_RDONLY);
+ if (fd < 0) {
+ /* process errors as appropriate */
+ fetch_file_process_error(ctx,
+ fetch_file_errno_to_http_code(errno));
+ return;
+ }
+
+ /* set buffer size */
+ buf_size = fdstat->st_size;
+
+ /* allocate the buffer storage */
+ if (buf_size > 0) {
+ buf = mmap(NULL, buf_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (buf == MAP_FAILED) {
+ msg.type = FETCH_ERROR;
+ msg.data.error = "Unable to map memory for file data
buffer";
+ fetch_file_send_callback(&msg, ctx);
+ close(fd);
+ 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",
+ guit->fetch->filetype(ctx->path))) {
+ goto fetch_file_process_aborted;
+ }
+
+ /* content length */
+ if (fetch_file_send_header(ctx, "Content-Length: %" PRIsizet,
+ fdstat->st_size)) {
+ goto fetch_file_process_aborted;
+ }
+
+ /* create etag */
+ if (fetch_file_send_header(ctx, "ETag: \"%10" PRId64 "\"",
+ (int64_t) fdstat->st_mtime)) {
+ goto fetch_file_process_aborted;
+ }
+
+ msg.type = FETCH_DATA;
+ msg.data.header_or_data.buf = (const uint8_t *) buf;
+ msg.data.header_or_data.len = buf_size;
+ fetch_file_send_callback(&msg, ctx);
+
+ if (ctx->aborted == false) {
+ msg.type = FETCH_FINISHED;
+ fetch_file_send_callback(&msg, ctx);
+ }
+
+fetch_file_process_aborted:
+
+ if (buf != NULL)
+ munmap(buf, buf_size);
+ close(fd);
+#else
+ fetch_msg msg;
+ char *buf;
+ size_t buf_size;
+
+ ssize_t tot_read = 0;
+ ssize_t res;
+
+ FILE *infile;
+
+ /* Check if we can just return not modified */
+ if (ctx->file_etag != 0 && ctx->file_etag == fdstat->st_mtime) {
+ fetch_set_http_code(ctx->fetchh, 304);
+ msg.type = FETCH_NOTMODIFIED;
+ fetch_file_send_callback(&msg, ctx);
+ return;
+ }
+
+ infile = fopen(ctx->path, "rb");
+ if (infile == NULL) {
+ /* process errors as appropriate */
+ fetch_file_process_error(ctx,
+ fetch_file_errno_to_http_code(errno));
+ return;
+ }
+
+ /* set buffer size */
+ buf_size = fdstat->st_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) {
+ msg.type = FETCH_ERROR;
+ msg.data.error =
+ "Unable to allocate memory for file data buffer";
+ fetch_file_send_callback(&msg, ctx);
+ fclose(infile);
+ 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",
+ guit->fetch->filetype(ctx->path))) {
+ goto fetch_file_process_aborted;
+ }
+
+ /* content length */
+ if (fetch_file_send_header(ctx, "Content-Length: %" PRIsizet,
+ fdstat->st_size)) {
+ goto fetch_file_process_aborted;
+ }
+
+ /* create etag */
+ if (fetch_file_send_header(ctx, "ETag: \"%10" PRId64 "\"",
+ (int64_t) fdstat->st_mtime)) {
+ goto fetch_file_process_aborted;
+ }
+
+ /* main data loop */
+ while (tot_read < fdstat->st_size) {
+ res = fread(buf, 1, buf_size, infile);
+ if (res == 0) {
+ if (feof(infile)) {
+ msg.type = FETCH_ERROR;
+ msg.data.error = "Unexpected EOF reading file";
+ fetch_file_send_callback(&msg, ctx);
+ goto fetch_file_process_aborted;
+ } else {
+ msg.type = FETCH_ERROR;
+ msg.data.error = "Error reading file";
+ fetch_file_send_callback(&msg, ctx);
+ goto fetch_file_process_aborted;
+ }
+ }
+ tot_read += res;
+
+ msg.type = FETCH_DATA;
+ msg.data.header_or_data.buf = (const uint8_t *) buf;
+ msg.data.header_or_data.len = res;
+ if (fetch_file_send_callback(&msg, ctx))
+ break;
+ }
+
+ if (ctx->aborted == false) {
+ msg.type = FETCH_FINISHED;
+ fetch_file_send_callback(&msg, ctx);
+ }
+
+fetch_file_process_aborted:
+
+ fclose(infile);
+ free(buf);
+#endif
+ 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) * SLEN("&") + 1);
+ if (nice_path == NULL) {
+ 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 if (*tmp == '&') {
+ *cnv++ = '&';
+ *cnv++ = 'a';
+ *cnv++ = 'm';
+ *cnv++ = 'p';
+ *cnv++ = ';';
+ } else {
+ *cnv++ = *tmp;
+ }
+ }
+ *cnv = '\0';
+
+ /* Construct a localised title string */
+ title_length = (cnv - nice_path) + strlen(messages_get("FileIndex"));
+ title = malloc(title_length + 1);
+
+ if (title == NULL) {
+ free(nice_path);
+ return NULL;
+ }
+
+ /* Set title to localised "Index of <nice_path>" */
+ snprintf(title, title_length, messages_get("FileIndex"), nice_path);
+
+ free(nice_path);
+
+ return title;
+}
+
+/**
+ * Generate an output row of the directory listing.
+ *
+ * \param ctx The file fetching context.
+ * \param ent current directory entry.
+ * \param even is the row an even row.
+ * \param buffer The output buffer.
+ * \param buffer_len The space available in the output buffer.
+ * \return NSERROR_OK or error code on faliure.
+ */
+static nserror
+process_dir_ent(struct fetch_file_context *ctx,
+ struct dirent *ent,
+ bool even,
+ char *buffer,
+ size_t buffer_len)
+{
+ nserror ret;
+ char *urlpath = NULL; /* buffer for leaf entry path */
+ struct stat ent_stat; /* stat result of leaf entry */
+ char datebuf[64]; /* buffer for date text */
+ char timebuf[64]; /* buffer for time text */
+ nsurl *url;
+
+ /* skip hidden files */
+ if (ent->d_name[0] == '.') {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ ret = netsurf_mkpath(&urlpath, NULL, 2, ctx->path, ent->d_name);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+
+ if (stat(urlpath, &ent_stat) != 0) {
+ ent_stat.st_mode = 0;
+ datebuf[0] = 0;
+ timebuf[0] = 0;
+ } else {
+ /* Get date in output format. a (day of week) and b
+ * (month) are both affected by the locale
+ */
+ if (strftime((char *)&datebuf, sizeof datebuf, "%a %d %b %Y",
+ localtime(&ent_stat.st_mtime)) == 0) {
+ datebuf[0] = '-';
+ datebuf[1] = 0;
+ }
+
+ /* Get time in output format */
+ if (strftime((char *)&timebuf, sizeof timebuf, "%H:%M",
+ localtime(&ent_stat.st_mtime)) == 0) {
+ timebuf[0] = '-';
+ timebuf[1] = 0;
+ }
+ }
+
+ ret = guit->file->path_to_nsurl(urlpath, &url);
+ if (ret != NSERROR_OK) {
+ free(urlpath);
+ return ret;
+ }
+
+ if (S_ISREG(ent_stat.st_mode)) {
+ /* regular file */
+ dirlist_generate_row(even,
+ false,
+ url,
+ ent->d_name,
+ guit->fetch->filetype(urlpath),
+ ent_stat.st_size,
+ datebuf, timebuf,
+ buffer, buffer_len);
+ } else if (S_ISDIR(ent_stat.st_mode)) {
+ /* directory */
+ dirlist_generate_row(even,
+ true,
+ url,
+ ent->d_name,
+ messages_get("FileDirectory"),
+ -1,
+ datebuf, timebuf,
+ buffer, buffer_len);
+ } else {
+ /* something else */
+ dirlist_generate_row(even,
+ false,
+ url,
+ ent->d_name,
+ "",
+ -1,
+ datebuf, timebuf,
+ buffer, buffer_len);
+ }
+
+ nsurl_unref(url);
+ free(urlpath);
+
+ return NSERROR_OK;
+}
+
+/**
+ * Comparison function for sorting directories.
+ *
+ * Correctly orders non zero-padded numerical parts.
+ * ie. produces "file1, file2, file10" rather than "file1, file10, file2".
+ *
+ * \param d1 first directory entry
+ * \param d2 second directory entry
+ */
+static int dir_sort_alpha(const struct dirent **d1, const struct dirent **d2)
+{
+ const char *s1 = (*d1)->d_name;
+ const char *s2 = (*d2)->d_name;
+
+ while (*s1 != '\0' && *s2 != '\0') {
+ if ((*s1 >= '0' && *s1 <= '9') &&
+ (*s2 >= '0' && *s2 <= '9')) {
+ int n1 = 0, n2 = 0;
+ while (*s1 >= '0' && *s1 <= '9') {
+ n1 = n1 * 10 + (*s1) - '0';
+ s1++;
+ }
+ while (*s2 >= '0' && *s2 <= '9') {
+ n2 = n2 * 10 + (*s2) - '0';
+ s2++;
+ }
+ if (n1 != n2) {
+ return n1 - n2;
+ }
+ if (*s1 == '\0' || *s2 == '\0')
+ break;
+ }
+ if (tolower(*s1) != tolower(*s2))
+ break;
+
+ s1++;
+ s2++;
+ }
+
+ return tolower(*s1) - tolower(*s2);
+}
+
+static void fetch_file_process_dir(struct fetch_file_context *ctx,
+ struct stat *fdstat)
+{
+ fetch_msg msg;
+ char buffer[1024]; /* Output buffer */
+ bool even = false; /* formatting flag */
+ char *title; /* pretty printed title */
+ nserror err; /* result from url routines */
+ nsurl *up; /* url of parent */
+
+ struct dirent **listing = NULL; /* directory entry listing */
+ int i; /* directory entry index */
+ int n; /* number of directory entries */
+
+ n = scandir(ctx->path, &listing, 0, dir_sort_alpha);
+ if (n < 0) {
+ fetch_file_process_error(ctx,
+ fetch_file_errno_to_http_code(errno));
+ return;
+ }
+
+ /* fetch is going to be successful */
+ fetch_set_http_code(ctx->fetchh, 200);
+
+ /* force no-cache */
+ if (fetch_file_send_header(ctx, "Cache-Control: no-cache"))
+ goto fetch_file_process_dir_aborted;
+
+ /* content type */
+ if (fetch_file_send_header(ctx, "Content-Type: text/html"))
+ goto fetch_file_process_dir_aborted;
+
+ msg.type = FETCH_DATA;
+ msg.data.header_or_data.buf = (const uint8_t *) buffer;
+
+ /* directory listing top */
+ dirlist_generate_top(buffer, sizeof buffer);
+ msg.data.header_or_data.len = strlen(buffer);
+ if (fetch_file_send_callback(&msg, ctx))
+ goto fetch_file_process_dir_aborted;
+
+ /* directory listing title */
+ title = gen_nice_title(ctx->path);
+ dirlist_generate_title(title, buffer, sizeof buffer);
+ free(title);
+ msg.data.header_or_data.len = strlen(buffer);
+ if (fetch_file_send_callback(&msg, ctx))
+ goto fetch_file_process_dir_aborted;
+
+ /* Print parent directory link */
+ err = nsurl_parent(ctx->url, &up);
+ if (err == NSERROR_OK) {
+ if (nsurl_compare(ctx->url, up, NSURL_COMPLETE) == false) {
+ /* different URL; have parent */
+ dirlist_generate_parent_link(nsurl_access(up),
+ buffer, sizeof buffer);
+
+ msg.data.header_or_data.len = strlen(buffer);
+ fetch_file_send_callback(&msg, ctx);
+ }
+ nsurl_unref(up);
+
+ if (ctx->aborted)
+ goto fetch_file_process_dir_aborted;
+
+ }
+
+ /* directory list headings */
+ dirlist_generate_headings(buffer, sizeof buffer);
+ msg.data.header_or_data.len = strlen(buffer);
+ if (fetch_file_send_callback(&msg, ctx))
+ goto fetch_file_process_dir_aborted;
+
+ for (i = 0; i < n; i++) {
+
+ err = process_dir_ent(ctx, listing[i], even, buffer,
+ sizeof(buffer));
+
+ if (err == NSERROR_OK) {
+ msg.data.header_or_data.len = strlen(buffer);
+ if (fetch_file_send_callback(&msg, ctx))
+ goto fetch_file_process_dir_aborted;
+
+ even = !even;
+ }
+ }
+
+ /* directory listing bottom */
+ dirlist_generate_bottom(buffer, sizeof buffer);
+ msg.data.header_or_data.len = strlen(buffer);
+ if (fetch_file_send_callback(&msg, ctx))
+ goto fetch_file_process_dir_aborted;
+
+ msg.type = FETCH_FINISHED;
+ fetch_file_send_callback(&msg, ctx);
+
+fetch_file_process_dir_aborted:
+
+ if (listing != NULL) {
+ for (i = 0; i < n; i++) {
+ free(listing[i]);
+ }
+ free(listing);
+ }
+}
+
+
+/* process a file fetch */
+static void fetch_file_process(struct fetch_file_context *ctx)
+{
+ struct stat fdstat; /**< The objects stat */
+
+ if (stat(ctx->path, &fdstat) != 0) {
+ /* process errors as appropriate */
+ fetch_file_process_error(ctx,
+ fetch_file_errno_to_http_code(errno));
+ return;
+ }
+
+ if (S_ISDIR(fdstat.st_mode)) {
+ /* directory listing */
+ fetch_file_process_dir(ctx, &fdstat);
+ return;
+ } else if (S_ISREG(fdstat.st_mode)) {
+ /* regular file */
+ fetch_file_process_plain(ctx, &fdstat);
+ return;
+ } else {
+ /* unhandled type of file */
+ fetch_file_process_error(ctx, 501);
+ }
+
+ return;
+}
+
+/** callback to poll for additional file fetch contents */
+static void fetch_file_poll(lwc_string *scheme)
+{
+ struct fetch_file_context *c, *save_ring = NULL;
+
+ while (ring != NULL) {
+ /* Take the first entry from the ring */
+ c = ring;
+ RING_REMOVE(ring, c);
+
+ /* 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) {
+ RING_INSERT(save_ring, c);
+ continue;
+ }
+
+ /* Only process non-aborted fetches */
+ if (c->aborted == false) {
+ /* file fetches can be processed in one go */
+ fetch_file_process(c);
+ }
+
+ /* And now finish */
+ fetch_remove_from_queues(c->fetchh);
+ fetch_free(c->fetchh);
+
+ }
+
+ /* Finally, if we saved any fetches which were locked, put them back
+ * into the ring for next time
+ */
+ ring = save_ring;
+}
+
+nserror fetch_file_register(void)
+{
+ lwc_string *scheme = lwc_string_ref(corestring_lwc_file);
+ const struct fetcher_operation_table fetcher_ops = {
+ .initialise = fetch_file_initialise,
+ .acceptable = fetch_file_can_fetch,
+ .setup = fetch_file_setup,
+ .start = fetch_file_start,
+ .abort = fetch_file_abort,
+ .free = fetch_file_free,
+ .poll = fetch_file_poll,
+ .finalise = fetch_file_finalise
+ };
+
+ return fetcher_add(scheme, &fetcher_ops);
+}
diff --git a/content/fetchers/file/file.h b/content/fetchers/file/file.h
new file mode 100644
index 0000000..5a5cfe8
--- /dev/null
+++ b/content/fetchers/file/file.h
@@ -0,0 +1,34 @@
+/*
+ * 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 scheme fetcher handler interface.
+ */
+
+#ifndef NETSURF_CONTENT_FETCHERS_FETCH_FILE_H
+#define NETSURF_CONTENT_FETCHERS_FETCH_FILE_H
+
+/**
+ * Register file scheme handler.
+ *
+ * \return NSERROR_OK on successful registration or error code on failure.
+ */
+nserror fetch_file_register(void);
+
+#endif
-----------------------------------------------------------------------
Summary of changes:
content/Makefile | 7 ++++---
content/fetch.c | 2 +-
content/fetchers/Makefile | 9 +++++++--
content/fetchers/file/Makefile | 3 +++
content/{ => fetchers/file}/dirlist.c | 2 +-
content/{ => fetchers/file}/dirlist.h | 9 +++++----
content/fetchers/{ => file}/file.c | 4 ++--
content/fetchers/{ => file}/file.h | 0
8 files changed, 23 insertions(+), 13 deletions(-)
create mode 100644 content/fetchers/file/Makefile
rename content/{ => fetchers/file}/dirlist.c (99%)
rename content/{ => fetchers/file}/dirlist.h (91%)
rename content/fetchers/{ => file}/file.c (99%)
rename content/fetchers/{ => file}/file.h (100%)
diff --git a/content/Makefile b/content/Makefile
index abc5a24..188d0f4 100644
--- a/content/Makefile
+++ b/content/Makefile
@@ -3,7 +3,6 @@
S_CONTENT := \
content.c \
content_factory.c \
- dirlist.c \
fetch.c \
hlcache.c \
llcache.c \
@@ -18,10 +17,12 @@ ifeq ($(NETSURF_FS_BACKING_STORE),YES)
endif
-# Content fetchers sources
+# Content fetcher sources
include content/fetchers/Makefile
-# Content handlers
+S_FETCHERS := $(addprefix content/,$(S_FETCHERS))
+
+# Content handler sources
include content/handlers/Makefile
S_CONTENT := $(addprefix content/,$(S_CONTENT))
diff --git a/content/fetch.c b/content/fetch.c
index 4cc7859..a260799 100644
--- a/content/fetch.c
+++ b/content/fetch.c
@@ -56,7 +56,7 @@
#include "content/fetchers/about.h"
#include "content/fetchers/curl.h"
#include "content/fetchers/data.h"
-#include "content/fetchers/file.h"
+#include "content/fetchers/file/file.h"
#include "javascript/fetcher.h"
#include "content/urldb.h"
diff --git a/content/fetchers/Makefile b/content/fetchers/Makefile
index 9c84793..e87a4e8 100644
--- a/content/fetchers/Makefile
+++ b/content/fetchers/Makefile
@@ -1,10 +1,15 @@
# Content fetchers sources
-S_FETCHERS_YES := data.c file.c about.c resource.c
+S_FETCHERS_YES := data.c about.c resource.c
S_FETCHERS_NO :=
S_FETCHERS_$(NETSURF_USE_CURL) += curl.c
-S_FETCHERS := $(addprefix content/fetchers/,$(S_FETCHERS_YES))
+S_FETCHERS := $(addprefix fetchers/,$(S_FETCHERS_YES))
+
+# File fetcher
+include content/fetchers/file/Makefile
+
+S_FETCHERS += $(addprefix fetchers/file/,$(S_FETCHER_FILE))
# The following files depend on the testament
content/fetchers/about.c: testament $(OBJROOT)/testament.h
diff --git a/content/fetchers/file/Makefile b/content/fetchers/file/Makefile
new file mode 100644
index 0000000..c22400a
--- /dev/null
+++ b/content/fetchers/file/Makefile
@@ -0,0 +1,3 @@
+# File fetcher sources
+
+S_FETCHER_FILE := dirlist.c file.c
diff --git a/content/dirlist.c b/content/fetchers/file/dirlist.c
similarity index 99%
rename from content/dirlist.c
rename to content/fetchers/file/dirlist.c
index 3f79e65..d49dc7f 100644
--- a/content/dirlist.c
+++ b/content/fetchers/file/dirlist.c
@@ -32,7 +32,7 @@
#include "netsurf/types.h"
#include "netsurf/plot_style.h"
-#include "content/dirlist.h"
+#include "dirlist.h"
#include "desktop/system_colour.h"
static int dirlist_filesize_calculate(unsigned long *bytesize);
diff --git a/content/dirlist.h b/content/fetchers/file/dirlist.h
similarity index 91%
rename from content/dirlist.h
rename to content/fetchers/file/dirlist.h
index 5cdaf75..3a0d48c 100644
--- a/content/dirlist.h
+++ b/content/fetchers/file/dirlist.h
@@ -16,14 +16,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Generate HTML content for displaying directory listings (interface).
+/**
+ * \file
+ * interface to generate HTML content for displaying directory listings.
*
* These functions should in general be called via the content interface.
*/
-#ifndef _NETSURF_CONTENT_DIRLIST_H_
-#define _NETSURF_CONTENT_DIRLIST_H_
+#ifndef NETSURF_CONTENT_DIRLIST_H_
+#define NETSURF_CONTENT_DIRLIST_H_
#include <stdbool.h>
diff --git a/content/fetchers/file.c b/content/fetchers/file/file.c
similarity index 99%
rename from content/fetchers/file.c
rename to content/fetchers/file/file.c
index bf2cc32..ff3a1b1 100644
--- a/content/fetchers/file.c
+++ b/content/fetchers/file/file.c
@@ -57,10 +57,10 @@
#include "netsurf/fetch.h"
#include "desktop/gui_internal.h"
-#include "content/dirlist.h"
#include "content/fetch.h"
#include "content/fetchers.h"
-#include "content/fetchers/file.h"
+#include "dirlist.h"
+#include "file.h"
/* Maximum size of read buffer */
#define FETCH_FILE_MAX_BUF_SIZE (1024 * 1024)
diff --git a/content/fetchers/file.h b/content/fetchers/file/file.h
similarity index 100%
rename from content/fetchers/file.h
rename to content/fetchers/file/file.h
--
NetSurf Browser
_______________________________________________
netsurf-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]