1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #include "download.h"
30
31 #include "davcontroller.h"
32 #include "window.h"
33
34 #include <cx/printf.h>
35
36 #include "config.h"
37
38 #include "system.h"
39 #include "common/context.h"
40
41 #include <libidav/config.h>
42 #include <libidav/utils.h>
43
44
45 static int uithr_download_update_progress(
void *data) {
46 DavFileDownload *download = data;
47 if(download->cancel) {
48 return 1;
49 }
50
51 time_t t = time(
NULL);
52
53 char *sz_total = util_size_str(
FALSE, download->progress.total_bytes);
54 char *sz_downloaded = util_size_str2(
FALSE, download->progress.transferred_bytes, download->progress.total_bytes,
2);
55 char *sz_downloaded_end = strchr(sz_downloaded,
' ');
56 if (sz_downloaded_end) {
57 *sz_downloaded_end =
0;
58 }
59
60 if (download->progress.total_bytes >
0) {
61 double progress = ((
double)download->progress.transferred_bytes / (
double)download->progress.total_bytes)*
100;
62 ui_set(download->progressbar, progress);
63 download->trans.progress = progress;
64
65
66
67
68
69
70
71 }
72
73
74 cxmutstr label1;
75 if (download->progress.total_files + download->progress.total_directories >
1) {
76 label1 = cx_asprintf(
77 "%s/%s %zu/%zu files",
78 sz_downloaded,
79 sz_total,
80 download->progress.transferred_files+download->progress.transferred_directories,
81 download->progress.total_files+download->progress.total_directories);
82 }
else {
83 label1 = cx_asprintf(
84 "%s/%s",
85 sz_downloaded,
86 sz_total);
87 }
88 ui_set(download->label_top_left, label1.ptr);
89
90 free(sz_total);
91 free(label1.ptr);
92
93 time_t start = download->progress.speedtest_start;
94 if(t >= download->progress.speedtest_start +
4) {
95 uint64_t bytesPerSeconds = dav_transfer_speed(&download->progress, t);
96 if(start >
0) {
97 char *szps = util_size_str(
FALSE, bytesPerSeconds);
98 cxmutstr label3 = cx_asprintf(
"%s/s", szps);
99 free(szps);
100 ui_set(download->label_bottom_left, label3.ptr);
101 free(label3.ptr);
102 }
103 }
104
105 return 1;
106 }
107
108 static size_t ddfile_write(
const void *buf,
size_t size,
size_t count,
void *stream) {
109 DDFile *file = stream;
110 if(file->download->cancel) {
111 return 0;
112 }
113
114 size_t w = fwrite(buf, size, count, file->fd);
115 file->download->progress.current_file_transferred += w;
116
117 file->download->progress.transferred_bytes += w;
118
119 if (file->download->progress.current_file_transferred > file->download->progress.current_file_size) {
120 size_t diff = file->download->progress.current_file_transferred - file->download->progress.current_file_size;
121 file->download->progress.current_file_size = file->download->progress.current_file_transferred;
122 file->download->progress.total_bytes += diff;
123 }
124
125 ui_call_mainthread(uithr_download_update_progress, file->download);
126
127 return w;
128 }
129
130 static int qthr_download_resource(
void *data) {
131 DDFile *file = data;
132 if(file->download->cancel) {
133 return 0;
134 }
135
136 file->download->progress.current_file_transferred =
0;
137 file->download->progress.current_file_size = file->size;
138
139 FILE *f = sys_fopen(file->to,
"wb");
140 if (!f) {
141 return 0;
142 }
143 file->fd = f;
144
145 DavResource *res = dav_resource_new(file->download->download_sn, file->path);
146 dav_get_content(res, file, (dav_write_func)ddfile_write);
147
148 file->download->progress.transferred_files++;
149
150 ui_call_mainthread(uithr_download_update_progress, file->download);
151
152 dav_resource_free(res);
153
154 fclose(f);
155
156 free(file->path);
157 free(file->to);
158 free(file);
159
160 return 0;
161 }
162
163 static int qthr_download_finished(
void *data) {
164 return 0;
165 }
166
167 static void uithr_download_finished(UiEvent *event,
void *data) {
168 DavFileDownload *download = data;
169 if(download->cancel) {
170 ui_set(download->label_bottom_left,
"Canceled");
171 }
172 if(download->dialog->ref >
1) {
173 ui_close(download->dialog);
174 }
175 ui_object_unref(download->dialog);
176 }
177
178
179 typedef struct DlStackElm {
180 DavResource *resource;
181 char *sub_path;
182 } DlStackElm;
183
184 static int jobthr_download_scan(
void *data) {
185 DavFileDownload *download = data;
186
187
188 SYS_STAT s;
189 if (!sys_stat(download->local_path, &s)) {
190 if (
S_ISDIR(s.st_mode)) {
191 download->isdirectory =
TRUE;
192 }
193 }
194
195 CxList *stack = cxLinkedListCreateSimple(
sizeof(DlStackElm));
196
197
198 DavResource *res = download->reslist;
199 while (res) {
200 DlStackElm elm;
201 elm.resource = res;
202 elm.sub_path = strdup(res->name);
203 cxListAdd(stack, &elm);
204
205 res = res->next;
206 }
207
208 while (cxListSize(stack) >
0 && !download->cancel) {
209 DlStackElm *elm = cxListAt(stack,
0);
210 DavResource *res = elm->resource;
211 char *sub_path = elm->sub_path;
212 cxListRemove(stack,
0);
213
214 if (res->iscollection) {
215 if (dav_load(res)) {
216
217 continue;
218 }
219
220
221 ui_call_mainthread(uithr_download_update_progress, download);
222
223 char *path = util_concat_path(download->local_path, sub_path);
224 int err = sys_mkdir(path);
225 free(path);
226 if (err) {
227
228 }
229
230 DavResource *child = res->children;
231 while (child) {
232 char *child_path = util_concat_path(sub_path, child->name);
233 DlStackElm childelm;
234 childelm.resource = child;
235 childelm.sub_path = child_path;
236 cxListAdd(stack, &childelm);
237
238 child = child->next;
239 }
240 }
else {
241
242 DDFile *file = malloc(
sizeof(DDFile));
243 file->download = download;
244 file->path = strdup(res->path);
245 file->size = res->contentlength;
246 if (download->isdirectory) {
247 file->to = util_concat_path(download->local_path, sub_path);
248 }
else {
249 file->to = strdup(download->local_path);
250 }
251
252
253 download->progress.total_files++;
254 download->progress.total_bytes += res->contentlength;
255
256
257 ui_call_mainthread(uithr_download_update_progress, download);
258
259 ui_threadpool_job(download->queue, download->dialog, qthr_download_resource, file,
NULL,
NULL);
260 }
261 }
262
263 ui_threadpool_job(download->queue, download->dialog, qthr_download_finished, download, uithr_download_finished, download);
264
265 cxListDestroy(stack);
266
267 return 0;
268 }
269
270 static void uithr_download_scan_finished(UiEvent *event,
void *data) {
271 DavFileDownload *download = data;
272
273 }
274
275 void action_download_cancel(UiEvent *event,
void *data) {
276 DavFileDownload *download = event->window;
277 if(!download->cancel) {
278 ui_set(download->label_bottom_left,
"Cancel...");
279 download->cancel =
TRUE;
280 }
281 }
282
283 static void dav_file_download_cleanup(DavFileDownload *download) {
284 application_remove_transfer(&download->trans);
285 ui_object_unref(download->browser->window);
286 }
287
288 DavFileDownload* dav_download_create(DavBrowser *browser, UiObject *dialog, DavResource *reslist,
const char *local_path) {
289 UiContext *ctx = dialog->ctx;
290 CxMempool *mp = ui_cx_mempool(ctx);
291 DavFileDownload *download = ui_malloc(ctx,
sizeof(DavFileDownload));
292 memset(download,
0,
sizeof(DavFileDownload));
293 download->dialog = dialog;
294 dialog->window = download;
295 ui_object_ref(dialog);
296 ui_object_ref(browser->window);
297
298 size_t label_len = strlen(reslist->name) +
16;
299 download->trans.label = cxCalloc(mp->allocator, label_len,
1);
300 download->trans.label_len = snprintf(download->trans.label, label_len,
"< %s%s", reslist->name, reslist->next ?
" ..." :
"");
301 download->trans.window = dialog;
302
303 download->browser = browser;
304 download->sn = reslist->session;
305 download->download_sn = dav_session_clone(download->sn);
306 download->reslist = reslist;
307 download->local_path = ui_strdup(dialog->ctx, local_path);
308
309 download->queue = ui_threadpool_create(
1);
310
311 cxMempoolRegister(mp, download->download_sn, (cx_destructor_func)dav_session_destroy);
312 cxMempoolRegister(mp, download->queue, (cx_destructor_func)ui_threadpool_destroy);
313 cxMempoolSetDestructor(download, (cx_destructor_func)dav_file_download_cleanup);
314
315 download->progressbar = ui_double_new(ctx,
"progressbar");
316 download->label_top_left = ui_string_new(ctx,
"label_top_left");
317 download->label_top_right = ui_string_new(ctx,
"label_top_right");
318 download->label_bottom_left = ui_string_new(ctx,
"label_bottom_left");
319 download->label_bottom_right = ui_string_new(ctx,
"label_bottom_right");
320
321 ui_set(download->label_top_left,
"");
322 ui_set(download->label_top_right,
"");
323 ui_set(download->label_bottom_left,
"");
324 ui_set(download->label_bottom_right,
"");
325 ui_set(download->progressbar,
0);
326
327 return download;
328 }
329
330 void dav_download_start(DavFileDownload *download) {
331 ui_show(download->dialog);
332 ui_job(download->dialog, jobthr_download_scan, download, uithr_download_scan_finished, download);
333 }
334