netsurf/windows/download.c
Vincent Sanders c105738fa3 Change LOG() macro to be varadic
This changes the LOG macro to be varadic removing the need for all
callsites to have double bracketing and allows for future improvement
on how we use the logging macros.

The callsites were changed with coccinelle and the changes checked by
hand. Compile tested for several frontends but not all.

A formatting annotation has also been added which allows the compiler
to check the parameters and types passed to the logging.
2015-05-28 16:08:46 +01:00

346 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 <sys/time.h>
#include "utils/config.h"
#include <shlobj.h>
#include <windows.h>
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/url.h"
#include "utils/nsurl.h"
#include "utils/utils.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 */
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 (nsurl_nice(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;
if (nsws_download_window_up(w) == false) {
warn_user(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;