summaryrefslogtreecommitdiff
path: root/frontends/windows/download.c
diff options
context:
space:
mode:
Diffstat (limited to 'frontends/windows/download.c')
-rw-r--r--frontends/windows/download.c346
1 files changed, 346 insertions, 0 deletions
diff --git a/frontends/windows/download.c b/frontends/windows/download.c
new file mode 100644
index 000000000..b281ea76a
--- /dev/null
+++ b/frontends/windows/download.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <limits.h>
+
+#include "utils/config.h"
+
+#include <shlobj.h>
+#include <windows.h>
+
+#include "utils/sys_time.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/url.h"
+#include "utils/nsurl.h"
+#include "utils/utils.h"
+#include "utils/string.h"
+#include "content/fetch.h"
+#include "desktop/gui_download.h"
+#include "desktop/download.h"
+
+#include "windows/download.h"
+#include "windows/window.h"
+#include "windows/gui.h"
+#include "windows/resourceid.h"
+#include "windows/schedule.h"
+
+struct gui_download_window {
+ HWND hwnd;
+ char *title;
+ char *filename;
+ char *domain;
+ char *time_left;
+ char *total_size;
+ char *original_total_size;
+ int size;
+ int downloaded;
+ unsigned int progress;
+ int time_remaining;
+ struct timeval start_time;
+ int speed;
+ int error;
+ struct gui_window *window;
+ FILE *file;
+ download_status status;
+};
+
+static bool downloading = false;
+static struct gui_download_window *download1;
+
+BOOL CALLBACK nsws_download_event_callback(HWND hwnd, UINT msg, WPARAM wparam,
+ LPARAM lparam);
+static void nsws_download_update_label(void *p);
+static void nsws_download_update_progress(void *p);
+static void nsws_download_clear_data(struct gui_download_window *w);
+
+static bool nsws_download_window_up(struct gui_download_window *w)
+{
+ w->hwnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DLG_DOWNLOAD),
+ gui_window_main_window(w->window),
+ nsws_download_event_callback);
+ if (w->hwnd == NULL) {
+ return false;
+ }
+ ShowWindow(w->hwnd, SW_SHOW);
+ return true;
+}
+
+static struct gui_download_window *
+gui_download_window_create(download_context *ctx, struct gui_window *gui)
+{
+ if (downloading) {
+ /* initial implementation */
+ win32_warning("1 download at a time please", 0);
+ return NULL;
+ }
+ downloading = true;
+ struct gui_download_window *w =
+ malloc(sizeof(struct gui_download_window));
+ if (w == NULL) {
+ win32_warning(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ int total_size = download_context_get_total_length(ctx);
+ char *domain, *filename, *destination;
+ nsurl *url = download_context_get_url(ctx);
+ bool unknown_size = (total_size == 0);
+ const char *size = (unknown_size) ?
+ messages_get("UnknownSize") :
+ human_friendly_bytesize(total_size);
+
+ if (nsurl_nice(url, &filename, false) != NSERROR_OK) {
+ filename = strdup(messages_get("UnknownFile"));
+ }
+ if (filename == NULL) {
+ win32_warning(messages_get("NoMemory"), 0);
+ free(w);
+ return NULL;
+ }
+
+ if (nsurl_has_component(url, NSURL_HOST)) {
+ domain = strdup(lwc_string_data(nsurl_get_component(url, NSURL_HOST)));
+ } else {
+ domain = strdup(messages_get("UnknownHost"));
+ }
+ if (domain == NULL) {
+ win32_warning(messages_get("NoMemory"), 0);
+ free(filename);
+ free(w);
+ return NULL;
+ }
+ destination = malloc(PATH_MAX);
+ if (destination == NULL) {
+ win32_warning(messages_get("NoMemory"), 0);
+ free(domain);
+ free(filename);
+ free(w);
+ return NULL;
+ }
+ SHGetFolderPath(NULL, CSIDL_DESKTOP, NULL, SHGFP_TYPE_CURRENT,
+ destination);
+ if (strlen(destination) < PATH_MAX - 2)
+ strcat(destination, "/");
+ if (strlen(destination) + strlen(filename) < PATH_MAX - 1)
+ strcat(destination, filename);
+ LOG("download %s [%s] from %s to %s", filename, size, domain, destination);
+ w->title = filename;
+ w->domain = domain;
+ w->size = total_size;
+ w->total_size = strdup(size);
+ if (w->total_size == NULL) {
+ win32_warning(messages_get("NoMemory"), 0);
+ free(destination);
+ free(domain);
+ free(filename);
+ free(w);
+ return NULL;
+ }
+ w->downloaded = 0;
+ w->speed = 0;
+ gettimeofday(&(w->start_time), NULL);
+ w->time_remaining = -1;
+ w->time_left = NULL;
+ w->status = DOWNLOAD_NONE;
+ w->filename = destination;
+ w->progress = 0;
+ w->error = 0;
+ w->window = gui;
+ w->file = fopen(destination, "wb");
+ if (w->file == NULL) {
+ win32_warning(messages_get("FileOpenWriteError"), destination);
+ free(destination);
+ free(domain);
+ free(filename);
+ free(w->total_size);
+ free(w->time_left);
+ free(w);
+ return NULL;
+ }
+ download1 = w;
+
+ if (nsws_download_window_up(w) == false) {
+ win32_warning(messages_get("NoMemory"), 0);
+ free(destination);
+ free(domain);
+ free(filename);
+ free(w->total_size);
+ free(w->time_left);
+ free(w);
+ return NULL;
+ }
+ return w;
+}
+
+
+BOOL CALLBACK nsws_download_event_callback(HWND hwnd, UINT msg, WPARAM wparam,
+ LPARAM lparam)
+{
+ HWND sub;
+ switch(msg){
+ case WM_INITDIALOG:
+ sub = GetDlgItem(hwnd, IDC_DOWNLOAD_LABEL);
+ nsws_download_update_label((void *)download1);
+ nsws_download_update_progress((void *)download1);
+ return TRUE;
+ case WM_COMMAND:
+ switch(LOWORD(wparam)) {
+ case IDOK:
+ if (download1->downloaded != download1->size)
+ return TRUE;
+ case IDCANCEL:
+ nsws_download_clear_data(download1);
+ download1 = NULL;
+ downloading = false;
+ EndDialog(hwnd, IDCANCEL);
+ return FALSE;
+ }
+ }
+ return FALSE;
+}
+
+void nsws_download_update_label(void *p)
+{
+ struct gui_download_window *w = p;
+ if (w->hwnd == NULL) {
+ win32_schedule(-1, nsws_download_update_label, p);
+ return;
+ }
+ HWND sub = GetDlgItem(w->hwnd, IDC_DOWNLOAD_LABEL);
+ char *size = human_friendly_bytesize(w->downloaded);
+ int i = 0, temp = w->time_remaining;
+ if (temp == -1) {
+ w->time_left = strdup(messages_get("UnknownSize"));
+ i = strlen(w->time_left);
+ } else {
+ do {
+ temp = temp / 10;
+ i++;
+ } while (temp > 2);
+ w->time_left = malloc(i + SLEN(" s") + 1);
+ if (w->time_left != NULL) {
+ if (w->time_remaining > 3600)
+ sprintf(w->time_left, "%d h",
+ w->time_remaining / 3600);
+ else if (w->time_remaining > 60)
+ sprintf(w->time_left, "%d m",
+ w->time_remaining / 60);
+ else
+ sprintf(w->time_left, "%d s",
+ w->time_remaining);
+ }
+ }
+ char label[strlen(w->title) + strlen(size) + strlen(w->total_size) +
+ + strlen(w->domain) + strlen(w->filename) +
+ SLEN("download from to \n[\t/\t]\n estimate of time"
+ " remaining ") + i + 1];
+ sprintf(label, "download %s from %s to %s\n[%s\t/\t%s] [%d%%]\n"
+ "estimate of time remaining %s", w->title, w->domain,
+ w->filename, size, w->total_size, w->progress / 100,
+ w->time_left);
+ if (w->time_left != NULL) {
+ free(w->time_left);
+ w->time_left = NULL;
+ }
+ SendMessage(sub, WM_SETTEXT, (WPARAM)0, (LPARAM)label);
+ if (w->progress < 10000) {
+ win32_schedule(500, nsws_download_update_label, p);
+ }
+}
+
+void nsws_download_update_progress(void *p)
+{
+ struct gui_download_window *w = p;
+ if (w->hwnd == NULL) {
+ win32_schedule(-1, nsws_download_update_progress, p);
+ return;
+ }
+ HWND sub = GetDlgItem(w->hwnd, IDC_DOWNLOAD_PROGRESS);
+ SendMessage(sub, PBM_SETPOS, (WPARAM)(w->progress / 100), 0);
+ if (w->progress < 10000) {
+ win32_schedule(500, nsws_download_update_progress, p);
+ }
+}
+
+void nsws_download_clear_data(struct gui_download_window *w)
+{
+ if (w == NULL)
+ return;
+ if (w->title != NULL)
+ free(w->title);
+ if (w->filename != NULL)
+ free(w->filename);
+ if (w->domain != NULL)
+ free(w->domain);
+ if (w->time_left != NULL)
+ free(w->time_left);
+ if (w->total_size != NULL)
+ free(w->total_size);
+ if (w->file != NULL)
+ fclose(w->file);
+ win32_schedule(-1, nsws_download_update_progress, (void *)w);
+ win32_schedule(-1, nsws_download_update_label, (void *)w);
+}
+
+
+static nserror
+gui_download_window_data(struct gui_download_window *w, const char *data,
+ unsigned int size)
+{
+ if ((w == NULL) || (w->file == NULL))
+ return NSERROR_SAVE_FAILED;
+ size_t res;
+ struct timeval val;
+ res = fwrite((void *)data, 1, size, w->file);
+ if (res != size)
+ LOG("file write error %d of %d", size - res, size);
+ w->downloaded += res;
+ w->progress = (unsigned int)(((long long)(w->downloaded) * 10000)
+ / w->size);
+ gettimeofday(&val, NULL);
+ w->time_remaining = (w->progress == 0) ? -1 :
+ (int)((val.tv_sec - w->start_time.tv_sec) *
+ (10000 - w->progress) / w->progress);
+ return NSERROR_OK;
+}
+
+static void gui_download_window_error(struct gui_download_window *w,
+ const char *error_msg)
+{
+ LOG("error %s", error_msg);
+}
+
+static void gui_download_window_done(struct gui_download_window *w)
+{
+ if (w == NULL)
+ return;
+ downloading = false;
+ if (w->hwnd != NULL)
+ EndDialog(w->hwnd, IDOK);
+ nsws_download_clear_data(w);
+}
+
+static struct gui_download_table download_table = {
+ .create = gui_download_window_create,
+ .data = gui_download_window_data,
+ .error = gui_download_window_error,
+ .done = gui_download_window_done,
+};
+
+struct gui_download_table *win32_download_table = &download_table;
+