diff options
Diffstat (limited to 'desktop/download.c')
-rw-r--r-- | desktop/download.c | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/desktop/download.c b/desktop/download.c new file mode 100644 index 000000000..7ec41c37d --- /dev/null +++ b/desktop/download.c @@ -0,0 +1,215 @@ +/* + * Copyright 2010 John-Mark Bell <jmb@netsurf-browser.org> + * + * 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 Core download context (implementation) + */ + +#include <assert.h> +#include <stdlib.h> + +#include "content/llcache.h" +#include "desktop/download.h" +#include "desktop/gui.h" +#include "utils/http.h" + +/** + * A context for a download + */ +struct download_context { + llcache_handle *llcache; /**< Low-level cache handle */ + struct gui_window *parent; /**< Parent window */ + + char *mime_type; /**< MIME type of download */ + unsigned long total_length; /**< Length of data, in bytes */ + + struct gui_download_window *window; /**< GUI download window */ +}; + +/** + * Process fetch headers for a download context. + * Extracts MIME type, total length, and creates gui_download_window + * + * \param ctx Context to process + * \return NSERROR_OK on success, appropriate error otherwise + */ +static nserror download_context_process_headers(download_context *ctx) +{ + const char *http_header; + char *mime_type; + http_parameter *params; + unsigned long length; + nserror error; + + /* Retrieve and parse Content-Type */ + http_header = llcache_handle_get_header(ctx->llcache, "Content-Type"); + if (http_header == NULL) + http_header = "text/plain"; + + error = http_parse_content_type(http_header, &mime_type, ¶ms); + if (error != NSERROR_OK) + return error; + + /* Don't care about parameters */ + http_parameter_list_destroy(params); + + /* Retrieve and parse Content-Length */ + http_header = llcache_handle_get_header(ctx->llcache, "Content-Length"); + if (http_header == NULL) + length = 0; + else + length = strtoul(http_header, NULL, 10); + + ctx->mime_type = mime_type; + ctx->total_length = length; + + /* Create the frontend window */ + ctx->window = gui_download_window_create(ctx, ctx->parent); + if (ctx->window == NULL) { + free(ctx->mime_type); + ctx->mime_type = NULL; + return NSERROR_NOMEM; + } + + return NSERROR_OK; +} + +/** + * Callback for low-level cache events + * + * \param handle Low-level cache handle + * \param event Event object + * \param pw Our context + * \return NSERROR_OK on success, appropriate error otherwise + */ +static nserror download_callback(llcache_handle *handle, + const llcache_event *event, void *pw) +{ + download_context *ctx = pw; + nserror error = NSERROR_OK; + + switch (event->type) { + case LLCACHE_EVENT_HAD_HEADERS: + error = download_context_process_headers(ctx); + if (error != NSERROR_OK) { + llcache_handle_abort(handle); + download_context_destroy(ctx); + } + + break; + + case LLCACHE_EVENT_HAD_DATA: + /* If we didn't know up-front that this fetch was for download, + * then we won't receive the HAD_HEADERS event. Catch up now. + */ + if (ctx->window == NULL) { + error = download_context_process_headers(ctx); + if (error != NSERROR_OK) { + llcache_handle_abort(handle); + download_context_destroy(ctx); + } + } + + if (error == NSERROR_OK) { + /** \todo Lose ugly cast */ + error = gui_download_window_data(ctx->window, + (char *) event->data.data.buf, + event->data.data.len); + if (error != NSERROR_OK) + llcache_handle_abort(handle); + } + + break; + + case LLCACHE_EVENT_DONE: + assert(ctx->window != NULL); + + gui_download_window_done(ctx->window); + + break; + + case LLCACHE_EVENT_ERROR: + if (ctx->window != NULL) + gui_download_window_error(ctx->window, event->data.msg); + + break; + + case LLCACHE_EVENT_PROGRESS: + break; + } + + return error; +} + +/* See download.h for documentation */ +nserror download_context_create(llcache_handle *llcache, + struct gui_window *parent) +{ + download_context *ctx; + + ctx = malloc(sizeof(*ctx)); + if (ctx == NULL) + return NSERROR_NOMEM; + + ctx->llcache = llcache; + ctx->parent = parent; + ctx->mime_type = NULL; + ctx->total_length = 0; + ctx->window = NULL; + + llcache_handle_change_callback(llcache, download_callback, ctx); + + return NSERROR_OK; +} + +/* See download.h for documentation */ +void download_context_destroy(download_context *ctx) +{ + llcache_handle_release(ctx->llcache); + + free(ctx->mime_type); + + /* Window is not owned by us, so don't attempt to destroy it */ + + free(ctx); +} + +/* See download.h for documentation */ +void download_context_abort(download_context *ctx) +{ + llcache_handle_abort(ctx->llcache); +} + +/* See download.h for documentation */ +const char *download_context_get_url(const download_context *ctx) +{ + return llcache_handle_get_url(ctx->llcache); +} + +/* See download.h for documentation */ +const char *download_context_get_mime_type(const download_context *ctx) +{ + return ctx->mime_type; +} + +/* See download.h for documentation */ +unsigned long download_context_get_total_length(const download_context *ctx) +{ + return ctx->total_length; +} + |