application/davcontroller.c

changeset 87
5360027fb282
parent 86
8e7c57c23133
--- a/application/davcontroller.c	Fri Nov 15 21:50:20 2024 +0100
+++ b/application/davcontroller.c	Sun Nov 17 15:19:32 2024 +0100
@@ -32,6 +32,8 @@
 #include <cx/printf.h>
 
 #include "config.h"
+#include "upload.h"
+#include "download.h"
 
 #include "system.h"
 #include "common/context.h"
@@ -442,726 +444,28 @@
 }
 
 
-// ------------------------------------- File Upload -------------------------------------
-
-typedef struct DavFileUpload {
-    UiObject *ui;
-    DavBrowser *browser;
-    DavSession *sn;
-    UiFileList files;
-    char *base_path;
-    UiThreadpool *queue;
-
-    size_t total_bytes;
-    size_t total_files;
-    size_t total_directories;
-    size_t uploaded_bytes;
-    size_t uploaded_files;
-    size_t uploaded_directories;
-
-    DavBool upload_file;
-    size_t current_file_size;
-    size_t current_file_upload;
-
-    char *current_file_name;
-
-    UiObject *dialog;
-    UiDouble *progress;
-    UiString *label_top_left;
-    UiString *label_top_right;
-    UiString *label_bottom_left;
-    UiString *label_bottom_right;
-
-    // The collection, the files are uploaded to
-    // It is only safe to access the collection ptr, if
-    // collection == browser->current && collection_ctn == browser->res_counter
-    // and obviously it can only be accessed from the UI thread
-    DavResource *collection;
-
-    // copy of browser->res_counter, used for integrity check
-    int64_t collection_ctn;
-
-    // current uploaded resource, created as part of the browser session
-    // only if collection == browser->current && collection_ctn == browser->res_counter
-    DavResource *current_resource;
-} DavFileUpload;
-
-typedef struct DUFile {
-    char *path;
-    char *upload_path;
-    size_t bytes;
-    DavBool isdirectory;
-    DavFileUpload *upload;
-    DavError error;
-} DUFile;
-
-static double upload_progress(DavFileUpload *upload) {
-    return ((double)upload->uploaded_bytes / (double)upload->total_bytes) * 100;
-}
-
-static void update_upload_labels(DavFileUpload *upload) {
-    char *sz_total = util_size_str(FALSE, upload->total_bytes);
-    char *sz_uploaded = util_size_str2(FALSE, upload->uploaded_bytes, upload->total_bytes, 2);
-    char *sz_uploaded_end = strchr(sz_uploaded, ' ');
-    if (sz_uploaded_end) {
-        *sz_uploaded_end = 0;
-    }
-
-    double progress = upload_progress(upload);
-    ui_set(upload->progress, upload_progress(upload));
-
-    cxmutstr label1;
-    if (upload->total_files + upload->total_directories > 1) {
-        label1 = cx_asprintf(
-            "%s/%s   %zu/%zu files",
-            sz_uploaded,
-            sz_total,
-            upload->uploaded_files+upload->uploaded_directories,
-            upload->total_files+upload->total_directories);
-    } else {
-        label1 = cx_asprintf(
-            "%s/%s",
-            sz_uploaded,
-            sz_total);
-    }
-    ui_set(upload->label_top_left, label1.ptr);
-
-    free(sz_total);
-    free(label1.ptr);
-
-    if (upload->current_file_size > 0) {
-        cxmutstr file_label = cx_asprintf("%s (%.0f%%)", upload->current_file_name, ((float)upload->current_file_upload/(float)upload->current_file_size)*100);
-        ui_set(upload->label_top_right, file_label.ptr);
-        free(file_label.ptr);
-    }
-}
-
-static int uithr_update_upload_labels(void *data) {
-    update_upload_labels(data);
-    return 0;
-}
-
-static void upload_dav_progress(DavResource *res, int64_t total, int64_t now, void *data) {
-    DavFileUpload *upload = data;
-    if (upload->upload_file) {
-        if (now > upload->current_file_size) {
-            // current_file_size is not accurate (either the file was changed after the last stat
-            // or we have some extra bytes because of encryption
-            // adjust current_file_size and the total upload size
-            int64_t extra = now - upload->current_file_size;
-            upload->current_file_size += extra;
-            upload->total_bytes += extra;
-        }
-
-        int64_t new_progress = now - upload->current_file_upload;
-        upload->uploaded_bytes += new_progress;
-        upload->current_file_upload = now;
-
-        ui_call_mainthread(uithr_update_upload_labels, upload);
-    }
-}
-
-
-typedef struct FileNameUpdate {
-    DavFileUpload *upload;
-    char *name;
-    char *path;
-    DavBool iscollection;
-} FileNameUpdate;
-
-static int uithr_update_file_label(FileNameUpdate *update) {
-    // replace upload->current_filename with update->name
-    if (update->upload->current_file_name) {
-        free(update->upload->current_file_name);
-    }
-    update->upload->current_file_name = update->name;
-
-    ui_set(update->upload->label_top_right, update->name);
-
-    DavFileUpload *upload = update->upload;
-    DavBrowser *browser = upload->browser;
-    // update the resource list in the browser, if the current collection has not changed
-    if (upload->collection == browser->current && upload->collection_ctn == browser->res_counter) {
-        char *parent = util_parent_path(update->path);
-        cxstring parent_s = cx_str(parent);
-        cxstring colpath_s = cx_str(upload->collection->path);
-        if (parent_s.length > 0 && parent_s.ptr[parent_s.length - 1] == '/') {
-            parent_s.length--;
-        }
-        if (colpath_s.length > 0 && colpath_s.ptr[colpath_s.length - 1] == '/') {
-            colpath_s.length--;
-        }
-
-        // only update, if the added resource has the current collection as parent
-        if (!cx_strcmp(parent_s, colpath_s)) {
-            DavResource *ui_res = dav_resource_new(upload->collection->session, update->path);
-            ui_res->iscollection = update->iscollection;
-            ui_res->lastmodified = time(NULL);
-            ui_res->creationdate = time(NULL);
-            upload->current_resource = ui_res;
-
-            ui_list_append(browser->resources, ui_res);
-            browser->resources->update(browser->resources, 0);
-        } else {
-            upload->current_resource = NULL; // maybe not necessary
-        }
-        free(parent);
-    }
-
-    free(update->path);
-    free(update);
-    return 0;
-}
-
-static int qthr_file_upload(void *data) {
-    DUFile *f = data;
-    DavFileUpload *upload = f->upload;
-    DavSession *sn = upload->sn;
-
-    FILE *in = sys_fopen(f->path, "rb");
-    if (!in) {
-        // TODO: error msg
-        return 0;
-    }
-
-    upload->upload_file = TRUE;
-    upload->current_file_size = f->bytes;
-    upload->current_file_upload = 0;
-
-    DavResource *res = dav_resource_new(sn, f->upload_path);
-
-    FileNameUpdate *ui_update = malloc(sizeof(FileNameUpdate));
-    ui_update->upload = upload;
-    ui_update->name = strdup(res->name);
-    ui_update->path = strdup(res->path);
-    ui_update->iscollection = FALSE;
-    ui_call_mainthread((ui_threadfunc)uithr_update_file_label, ui_update);
-
-    dav_set_content(res, in, (dav_read_func)fread, (dav_seek_func)fseek);
-    if (dav_store(res)) {
-        f->error = sn->error;
-    }
-    dav_resource_free(res);
-
-    fclose(in);
-
-    upload->upload_file = FALSE;
-
-    return 0;
-}
-
-static void uithr_file_uploaded(UiEvent *event, void *data) {
-    DUFile *file = data;
-    DavFileUpload *upload = file->upload;
-
-    upload->uploaded_files++;
-    //upload->uploaded_bytes += file->bytes;
-
-    double progress = upload_progress(upload);
-    ui_set(upload->progress, upload_progress(upload));
-
-    update_upload_labels(upload);
-
-    // update resource content length in the browser 
-    DavBrowser *browser = upload->browser;
-    if (upload->collection == browser->current && upload->collection_ctn == browser->res_counter) {
-        if (upload->current_resource) {
-            upload->current_resource->contentlength = upload->current_file_upload;
-            browser->resources->update(browser->resources, 0);
-        }
-    }
-    upload->current_resource = NULL;
-
-    free(file->path);
-    free(file->upload_path);
-}
-
-static int qthr_dir_upload(void *data) {
-    DUFile *f = data;
-    DavFileUpload *upload = f->upload;
-    DavSession *sn = upload->sn;
-
-    DavResource *res = dav_resource_new(sn, f->upload_path);
-    res->iscollection = TRUE;
-
-    FileNameUpdate *ui_update = malloc(sizeof(FileNameUpdate));
-    ui_update->upload = upload;
-    ui_update->name = strdup(res->name);
-    ui_update->path = strdup(res->path);
-    ui_update->iscollection = TRUE;
-    ui_call_mainthread((ui_threadfunc)uithr_update_file_label, ui_update);
-
-    if (dav_create(res)) {
-        f->error = sn->error;
-    }
-
-    dav_resource_free(res);
-
-    return 0;
-}
-
-static void uithr_dir_uploaded(UiEvent *event, void *data) {
-    DUFile *file = data;
-    DavFileUpload *upload = file->upload;
-
-    upload->uploaded_directories++;
-
-    update_upload_labels(upload);
-
-    upload->current_resource = NULL;
-
-    free(file->path);
-    free(file->upload_path);
-}
-
-static int qthr_upload_finished(void *data) {
-    return 0;
-}
-
-static void uithr_upload_finished(UiEvent *event, void *data) {
-    DavFileUpload *upload = data;
-    ui_threadpool_destroy(upload->queue);
-
-    free(upload->base_path);
-    dav_session_destroy(upload->sn);
-}
-
-static int jobthr_upload_scan(void *data) {
-    DavFileUpload *upload = data;
-
-    CxList *stack = cxLinkedListCreateSimple(CX_STORE_POINTERS);
-    for (int i = 0; i < upload->files.nfiles; i++) {
-        DUFile *f = malloc(sizeof(DUFile));
-        f->path = strdup(upload->files.files[i]);
-        f->upload_path = util_concat_path(upload->base_path, util_path_file_name(f->path));
-        f->isdirectory = FALSE;
-        f->bytes = 0;
-        f->upload = upload;
-        f->error = 0;
-        cxListInsert(stack, 0, f);
-    }
-
-    while (cxListSize(stack) > 0) {
-        DUFile *f = cxListAt(stack, 0);
-
-        char *path = util_concat_path(upload->base_path, f->upload_path);
-        cxListRemove(stack, 0);
-
-        SYS_STAT s;
-        if (!sys_stat(f->path, &s)) {
-            if (S_ISDIR(s.st_mode)) {
-                f->isdirectory = TRUE;
-                upload->total_directories++;
-                ui_threadpool_job(upload->queue, upload->ui, qthr_dir_upload, f, uithr_dir_uploaded, f);
-
-                SYS_DIR dir = sys_opendir(f->path);
-                if (dir) {
-                    SysDirEnt *entry;
-                    int nument = 0;
-                    while((entry = sys_readdir(dir)) != NULL) {
-                        if(!strcmp(entry->name, ".") || !strcmp(entry->name, "..")) {
-                            continue;
-                        }
-
-                        cxmutstr newpath = util_concat_sys_path(cx_str(f->path), cx_str(entry->name));
-                        char *new_upload_path = util_concat_path(f->upload_path, entry->name);
-
-                        DUFile *child = malloc(sizeof(DUFile));
-                        child->path = newpath.ptr;
-                        child->upload_path = new_upload_path;
-                        child->isdirectory = FALSE;
-                        child->bytes = 0;
-                        child->upload = upload;
-                        child->error = 0;
-                        cxListAdd(stack, child);
-                    }
-
-                    sys_closedir(dir);
-                }
-            } else if (S_ISREG(s.st_mode)) {
-                f->isdirectory = FALSE;
-                f->bytes = s.st_size;
-                upload->total_files++;
-                upload->total_bytes += s.st_size;
-                ui_threadpool_job(upload->queue, upload->ui, qthr_file_upload, f, uithr_file_uploaded, f);
-            }
-        }
-    } // TODO: else error msg
-
-    ui_threadpool_job(upload->queue, upload->ui, qthr_upload_finished, upload, uithr_upload_finished, upload);
-
-    ui_filelist_free(upload->files);
-
-    return 0;
-}
-
-static void uithr_upload_scan_finished(UiEvent *event, void *data) {
-    DavFileUpload *upload = data;
-
-    update_upload_labels(upload);
-}
-
-static void upload_window_closed(UiEvent *event, void *data) {
-    // noop, prevents context destruction
-}
-
 void davbrowser_upload_files(UiObject *ui, DavBrowser *browser, UiFileList files) {
     if (!browser->sn) {
         return; // TODO: error msg
     }
-
-    // we need a clone of the current session, because the upload
-    // is done in a separate thread
-    DavSession *upload_session = dav_session_clone(browser->sn);
-
-    // create upload obj, that contains all relevant data for the upload
-    DavFileUpload *upload = malloc(sizeof(DavFileUpload));
-    memset(upload, 0, sizeof(DavFileUpload));
-
-    dav_session_set_progresscallback(upload_session, NULL, upload_dav_progress, upload);
-
-    upload->ui = ui;
-    upload->browser = browser;
-    upload->sn = upload_session;
-    upload->files = files;
-    upload->base_path = strdup(browser->current->path);
-    upload->queue = ui_threadpool_create(1);
-
-    upload->collection = browser->current;
-    upload->collection_ctn = browser->res_counter;
-
-    // create upload progress window
+    
     cxmutstr wtitle = cx_asprintf("Upload to: %s", ui_get(browser->path));
-    UiObject *dialog = ui_simple_window(wtitle.ptr, upload);
-    ui_context_closefunc(dialog->ctx, upload_window_closed, NULL);
+    UiObject *dialog = ui_simple_window(wtitle.ptr, NULL);
     free(wtitle.ptr);
-    upload->dialog = dialog;
-    ui_window_size(dialog, 550, 120);
-    upload->progress = ui_double_new(dialog->ctx, NULL);
-    upload->label_top_left = ui_string_new(dialog->ctx, NULL);
-    upload->label_top_right = ui_string_new(dialog->ctx, NULL);
-    upload->label_bottom_left = ui_string_new(dialog->ctx, NULL);
-    upload->label_bottom_right = ui_string_new(dialog->ctx, NULL);
-
-    ui_grid(dialog, .margin = 10, .spacing = 10, .fill = TRUE) {
-        ui_llabel(dialog, .value = upload->label_top_left, .hexpand = TRUE);
-        ui_rlabel(dialog, .value = upload->label_top_right);
-        ui_newline(dialog);
-
-        ui_progressbar(dialog, .value = upload->progress, .colspan = 2, .hexpand = TRUE);
-        ui_newline(dialog);
-
-        ui_llabel(dialog, .value = upload->label_bottom_left);
-        ui_rlabel(dialog, .value = upload->label_bottom_right);
-        ui_newline(dialog);
-    }
-
-    ui_set(upload->label_top_left, "");
-    ui_set(upload->label_top_right, "");
-    ui_set(upload->label_bottom_left, "");
-    ui_set(upload->label_bottom_right, "");
-    ui_set(upload->progress, 0);
-
-    ui_show(dialog);
-
-    // start upload and stat threads
-    ui_job(ui, jobthr_upload_scan, upload, uithr_upload_scan_finished, upload);
-}
-
-
-// ------------------------------------- File Download -------------------------------------
-
-typedef struct DavFileDownload {
-    UiObject *ui;
-    DavBrowser *browser;
-
-    DavSession *sn;
-    DavSession *download_sn;
-    DavResource *reslist;
-    char *local_path;
-    DavBool isdirectory;
-
-    UiThreadpool *queue;
 
-    size_t total_bytes;
-    size_t total_files;
-    size_t total_directories;
-    size_t downloaded_bytes;
-    size_t downloaded_files;
-    size_t downloaded_directories;
-
-    size_t current_file_size;
-    size_t current_file_downloaded;
-
-    UiObject *dialog;
-    UiDouble *progress;
-    UiString *label_top_left;
-    UiString *label_top_right;
-    UiString *label_bottom_left;
-    UiString *label_bottom_right;
-} DavFileDownload;
-
-
-static int uithr_download_update_progress(void *data) {
-    DavFileDownload *download = data;
-    char *sz_total = util_size_str(FALSE, download->total_bytes);
-    char *sz_downloaded = util_size_str2(FALSE, download->downloaded_bytes, download->total_bytes, 2);
-    char *sz_downloaded_end = strchr(sz_downloaded, ' ');
-    if (sz_downloaded_end) {
-        *sz_downloaded_end = 0;
-    }
-    
-    if (download->total_bytes > 0) {
-        double progress = (double)download->downloaded_bytes / (double)download->total_bytes;
-        ui_set(download->progress, progress*100);
-    }
-    
-
-    cxmutstr label1;
-    if (download->total_files + download->total_directories > 1) {
-        label1 = cx_asprintf(
-            "%s/%s   %zu/%zu files",
-            sz_downloaded,
-            sz_total,
-            download->downloaded_files+download->downloaded_directories,
-            download->total_files+download->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);
-    
-
-    return 1;
-}
-
-// dav download file
-typedef struct DDFile {
-    DavFileDownload *download;
-    size_t size;
-    char *path;
-    char *to;
-    FILE *fd;
-} DDFile;
-
-static size_t ddfile_write(const void *buf, size_t size, size_t count, void *stream) {
-    DDFile *file = stream;
-
-    size_t w = fwrite(buf, size, count, file->fd);
-    file->download->current_file_downloaded += w;
-
-    file->download->downloaded_bytes += w;
-
-    if (file->download->current_file_downloaded > file->download->current_file_size) {
-        size_t diff = file->download->current_file_downloaded - file->download->current_file_size;
-        file->download->current_file_size = file->download->current_file_downloaded;
-        file->download->total_bytes += diff;
-    }
-
-    ui_call_mainthread(uithr_download_update_progress, file->download);
-
-    return w;
+    DavFileUpload *upload = dav_upload_create(browser, dialog, files);
+    transfer_window_init(dialog, action_upload_cancel);
+    dav_upload_start(upload);
 }
 
-static int qthr_download_resource(void *data) {
-    DDFile *file = data;
-
-    file->download->current_file_downloaded = 0;
-    file->download->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->downloaded_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;
-    printf("download finished\n");
-    ui_object_unref(download->dialog);
-}
-
-
-typedef struct DlStackElm {
-    DavResource *resource;
-    char *sub_path;
-} DlStackElm;
-
-static int jobthr_download_scan(void *data) {
-    DavFileDownload *download = data;
-    DavBrowser *browser = download->browser;
-
-    // check if the specified local location is a directory
-    SYS_STAT s;
-    if (!sys_stat(download->local_path, &s)) {
-        if (S_ISDIR(s.st_mode)) {
-            download->isdirectory = TRUE;
-        }
-    }
-
-    CxList *stack = cxLinkedListCreateSimple(sizeof(DlStackElm));
-
-    // add selected files to the download queue
-    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) {
-        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)) {
-                // TODO: handle error
-                continue;
-            }
-
-            // update ui
-            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) {
-                // TODO: handle error
-            }
-
-            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 {
-            // add the file to the download queue
-            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);
-            }
-
-            // stats
-            download->total_files++;
-            download->total_bytes += res->contentlength;
-
-            // update ui
-            ui_call_mainthread(uithr_download_update_progress, download);
-
-            ui_threadpool_job(download->queue, download->ui, qthr_download_resource, file, NULL, NULL);
-        } 
-    }
+void davbrowser_download(UiObject *ui, DavBrowser *browser, DavResource *reslist, const char *local_path) {
+    cxmutstr wtitle = cx_asprintf("Download to: %s", local_path);
+    UiObject *dialog = ui_simple_window(wtitle.ptr, NULL);
+    free(wtitle.ptr);
     
-    ui_threadpool_job(download->queue, download->ui, 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;
-
-}
-
-static void download_window_closed(UiEvent *event, void *data) {
-
-}
-
-
-void davbrowser_download(UiObject *ui, DavBrowser *browser, DavResource *reslist, const char *local_path) {
-    DavFileDownload *download = malloc(sizeof(DavFileDownload));
-    memset(download, 0, sizeof(DavFileDownload));
-
-    download->ui = ui;
-    download->browser = browser;
-    download->sn = reslist->session;
-    download->download_sn = dav_session_clone(download->sn);
-    download->reslist = reslist; // TODO: is this safe or do we need a copy?
-    download->local_path = strdup(local_path);
-
-    download->queue = ui_threadpool_create(1);
-
-    // create download progress window
-    cxmutstr wtitle = cx_asprintf("Download to: %s", local_path);
-    UiObject *dialog = ui_simple_window(wtitle.ptr, download);
-    ui_context_closefunc(dialog->ctx, download_window_closed, NULL);
-    free(wtitle.ptr);
-    download->dialog = dialog;
-    ui_window_size(dialog, 550, 120);
-    download->progress = ui_double_new(dialog->ctx, NULL);
-    download->label_top_left = ui_string_new(dialog->ctx, NULL);
-    download->label_top_right = ui_string_new(dialog->ctx, NULL);
-    download->label_bottom_left = ui_string_new(dialog->ctx, NULL);
-    download->label_bottom_right = ui_string_new(dialog->ctx, NULL);
-
-    ui_grid(dialog, .margin = 10, .spacing = 10, .fill = TRUE) {
-        ui_llabel(dialog, .value = download->label_top_left, .hexpand = TRUE);
-        ui_rlabel(dialog, .value = download->label_top_right);
-        ui_newline(dialog);
-
-        ui_progressbar(dialog, .value = download->progress, .min = 0, .max = 100, .colspan = 2, .hexpand = TRUE);
-        ui_newline(dialog);
-
-        ui_llabel(dialog, .value = download->label_bottom_left);
-        ui_rlabel(dialog, .value = download->label_bottom_right);
-        ui_newline(dialog);
-    }
-
-    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->progress, 0);
-
-    ui_show(dialog);
-    
-    ui_object_ref(dialog);
-
-    // start upload and stat threads
-    ui_job(ui, jobthr_download_scan, download, uithr_download_scan_finished, download);
+    DavFileDownload *download = dav_download_create(browser, dialog, reslist, local_path);
+    transfer_window_init(dialog, action_download_cancel);
+    dav_download_start(download);
 }
 
 

mercurial