/* * 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 <sys/time.h> #include "utils/config.h" #include <shlobj.h> #include <windows.h> #include "content/fetch.h" #include "desktop/gui.h" #include "desktop/download.h" #include "utils/log.h" #include "utils/messages.h" #include "utils/url.h" #include "utils/nsurl.h" #include "utils/utils.h" #include "windows/download.h" #include "windows/gui.h" #include "windows/resourceid.h" #include "windows/schedule.h" static bool downloading = false; static struct gui_download_window *download1; static bool nsws_download_window_up(struct gui_download_window *w); 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 struct gui_download_window * gui_download_window_create(download_context *ctx, struct gui_window *gui) { if (downloading) { /* initial implementation */ warn_user("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) { warn_user(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 (url_nice(nsurl_access(url), &filename, false) != NSERROR_OK) filename = strdup(messages_get("UnknownFile")); if (filename == NULL) { warn_user(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) { warn_user(messages_get("NoMemory"), 0); free(filename); free(w); return NULL; } destination = malloc(PATH_MAX); if (destination == NULL) { warn_user(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) { warn_user(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) { warn_user(messages_get("FileOpenWriteError"), destination); free(destination); free(domain); free(filename); free(w->total_size); free(w->time_left); free(w); return NULL; } download1 = w; nsws_download_window_up(w); return w; } 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) { warn_user(messages_get("NoMemory"), 0); return false; } ShowWindow(w->hwnd, SW_SHOW); return true; } 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;