#include "download.h"
#include "davcontroller.h"
#include "window.h"
#include <cx/printf.h>
#include "config.h"
#include "system.h"
#include "common/context.h"
#include <libidav/config.h>
#include <libidav/utils.h>
static int uithr_download_update_progress(
void *data) {
DavFileDownload *download = data;
if(download->cancel) {
return 1;
}
time_t t = time(
NULL);
char *sz_total = util_size_str(
FALSE, download->progress.total_bytes);
char *sz_downloaded = util_size_str2(
FALSE, download->progress.transferred_bytes, download->progress.total_bytes,
2);
char *sz_downloaded_end = strchr(sz_downloaded,
' ');
if (sz_downloaded_end) {
*sz_downloaded_end =
0;
}
if (download->progress.total_bytes >
0) {
double progress = ((
double)download->progress.transferred_bytes / (
double)download->progress.total_bytes)*
100;
ui_set(download->progressbar, progress);
download->trans.progress = progress;
}
cxmutstr label1;
if (download->progress.total_files + download->progress.total_directories >
1) {
label1 = cx_asprintf(
"%s/%s %zu/%zu files",
sz_downloaded,
sz_total,
download->progress.transferred_files+download->progress.transferred_directories,
download->progress.total_files+download->progress.total_directories);
}
else {
label1 = cx_asprintf(
"%s/%s",
sz_downloaded,
sz_total);
}
ui_set(download->label_top_left, label1.ptr);
free(sz_total);
free(label1.ptr);
time_t start = download->progress.speedtest_start;
if(t >= download->progress.speedtest_start +
4) {
uint64_t bytesPerSeconds = dav_transfer_speed(&download->progress, t);
if(start >
0) {
char *szps = util_size_str(
FALSE, bytesPerSeconds);
cxmutstr label3 = cx_asprintf(
"%s/s", szps);
free(szps);
ui_set(download->label_bottom_left, label3.ptr);
free(label3.ptr);
}
}
return 1;
}
static size_t ddfile_write(
const void *buf,
size_t size,
size_t count,
void *stream) {
DDFile *file = stream;
if(file->download->cancel) {
return 0;
}
size_t w = fwrite(buf, size, count, file->fd);
file->download->progress.current_file_transferred += w;
file->download->progress.transferred_bytes += w;
if (file->download->progress.current_file_transferred > file->download->progress.current_file_size) {
size_t diff = file->download->progress.current_file_transferred - file->download->progress.current_file_size;
file->download->progress.current_file_size = file->download->progress.current_file_transferred;
file->download->progress.total_bytes += diff;
}
ui_call_mainthread(uithr_download_update_progress, file->download);
return w;
}
static int qthr_download_resource(
void *data) {
DDFile *file = data;
if(file->download->cancel) {
return 0;
}
file->download->progress.current_file_transferred =
0;
file->download->progress.current_file_size = file->size;
FILE *f = sys_fopen(file->to,
"wb");
if (!f) {
return 0;
}
file->fd = f;
DavResource *res = dav_resource_new(file->download->download_sn, file->path);
dav_get_content(res, file, (dav_write_func)ddfile_write);
file->download->progress.transferred_files++;
ui_call_mainthread(uithr_download_update_progress, file->download);
dav_resource_free(res);
fclose(f);
free(file->path);
free(file->to);
free(file);
return 0;
}
static int qthr_download_finished(
void *data) {
return 0;
}
static void uithr_download_finished(UiEvent *event,
void *data) {
DavFileDownload *download = data;
if(download->cancel) {
ui_set(download->label_bottom_left,
"Canceled");
}
if(download->dialog->ref >
1) {
ui_close(download->dialog);
}
ui_object_unref(download->dialog);
}
typedef struct DlStackElm {
DavResource *resource;
char *sub_path;
} DlStackElm;
static int jobthr_download_scan(
void *data) {
DavFileDownload *download = data;
SYS_STAT s;
if (!sys_stat(download->local_path, &s)) {
if (
S_ISDIR(s.st_mode)) {
download->isdirectory =
TRUE;
}
}
CxList *stack = cxLinkedListCreateSimple(
sizeof(DlStackElm));
DavResource *res = download->reslist;
while (res) {
DlStackElm elm;
elm.resource = res;
elm.sub_path = strdup(res->name);
cxListAdd(stack, &elm);
res = res->next;
}
while (cxListSize(stack) >
0 && !download->cancel) {
DlStackElm *elm = cxListAt(stack,
0);
DavResource *res = elm->resource;
char *sub_path = elm->sub_path;
cxListRemove(stack,
0);
if (res->iscollection) {
if (dav_load(res)) {
continue;
}
ui_call_mainthread(uithr_download_update_progress, download);
char *path = util_concat_path(download->local_path, sub_path);
int err = sys_mkdir(path);
free(path);
if (err) {
}
DavResource *child = res->children;
while (child) {
char *child_path = util_concat_path(sub_path, child->name);
DlStackElm childelm;
childelm.resource = child;
childelm.sub_path = child_path;
cxListAdd(stack, &childelm);
child = child->next;
}
}
else {
DDFile *file = malloc(
sizeof(DDFile));
file->download = download;
file->path = strdup(res->path);
file->size = res->contentlength;
if (download->isdirectory) {
file->to = util_concat_path(download->local_path, sub_path);
}
else {
file->to = strdup(download->local_path);
}
download->progress.total_files++;
download->progress.total_bytes += res->contentlength;
ui_call_mainthread(uithr_download_update_progress, download);
ui_threadpool_job(download->queue, download->dialog, qthr_download_resource, file,
NULL,
NULL);
}
}
ui_threadpool_job(download->queue, download->dialog, qthr_download_finished, download, uithr_download_finished, download);
cxListDestroy(stack);
return 0;
}
static void uithr_download_scan_finished(UiEvent *event,
void *data) {
DavFileDownload *download = data;
}
void action_download_cancel(UiEvent *event,
void *data) {
DavFileDownload *download = event->window;
if(!download->cancel) {
ui_set(download->label_bottom_left,
"Cancel...");
download->cancel =
TRUE;
}
}
static void dav_file_download_cleanup(DavFileDownload *download) {
application_remove_transfer(&download->trans);
ui_object_unref(download->browser->window);
}
DavFileDownload* dav_download_create(DavBrowser *browser, UiObject *dialog, DavResource *reslist,
const char *local_path) {
UiContext *ctx = dialog->ctx;
CxMempool *mp = ui_cx_mempool(ctx);
DavFileDownload *download = ui_malloc(ctx,
sizeof(DavFileDownload));
memset(download,
0,
sizeof(DavFileDownload));
download->dialog = dialog;
dialog->window = download;
ui_object_ref(dialog);
ui_object_ref(browser->window);
size_t label_len = strlen(reslist->name) +
16;
download->trans.label = cxCalloc(mp->allocator, label_len,
1);
download->trans.label_len = snprintf(download->trans.label, label_len,
"< %s%s", reslist->name, reslist->next ?
" ..." :
"");
download->trans.window = dialog;
download->browser = browser;
download->sn = reslist->session;
download->download_sn = dav_session_clone(download->sn);
download->reslist = reslist;
download->local_path = ui_strdup(dialog->ctx, local_path);
download->queue = ui_threadpool_create(
1);
cxMempoolRegister(mp, download->download_sn, (cx_destructor_func)dav_session_destroy);
cxMempoolRegister(mp, download->queue, (cx_destructor_func)ui_threadpool_destroy);
cxMempoolSetDestructor(download, (cx_destructor_func)dav_file_download_cleanup);
download->progressbar = ui_double_new(ctx,
"progressbar");
download->label_top_left = ui_string_new(ctx,
"label_top_left");
download->label_top_right = ui_string_new(ctx,
"label_top_right");
download->label_bottom_left = ui_string_new(ctx,
"label_bottom_left");
download->label_bottom_right = ui_string_new(ctx,
"label_bottom_right");
ui_set(download->label_top_left,
"");
ui_set(download->label_top_right,
"");
ui_set(download->label_bottom_left,
"");
ui_set(download->label_bottom_right,
"");
ui_set(download->progressbar,
0);
return download;
}
void dav_download_start(DavFileDownload *download) {
ui_show(download->dialog);
ui_job(download->dialog, jobthr_download_scan, download, uithr_download_scan_finished, download);
}