347 lines
8.9 KiB
C
347 lines
8.9 KiB
C
/*
|
|
* 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;
|
|
|