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 "upload.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
46 static double upload_progress(DavFileUpload *upload) {
47 return ((
double)upload->progress.transferred_bytes / (
double)upload->progress.total_bytes) *
100;
48 }
49
50 static void update_upload_labels(DavFileUpload *upload) {
51 char *sz_total = util_size_str(
FALSE, upload->progress.total_bytes);
52 char *sz_uploaded = util_size_str2(
FALSE, upload->progress.transferred_bytes, upload->progress.total_bytes,
2);
53 char *sz_uploaded_end = strchr(sz_uploaded,
' ');
54 if (sz_uploaded_end) {
55 *sz_uploaded_end =
0;
56 }
57
58 double progress = upload_progress(upload);
59 ui_set(upload->progressbar, progress);
60 upload->trans.progress = progress;
61 time_t t = time(
NULL);
62
63
64
65
66
67
68
69
70 cxmutstr label1;
71 if (upload->progress.total_files + upload->progress.total_directories >
1) {
72 label1 = cx_asprintf(
73 "%s/%s %zu/%zu files",
74 sz_uploaded,
75 sz_total,
76 upload->progress.transferred_files+upload->progress.transferred_directories,
77 upload->progress.total_files+upload->progress.total_directories);
78 }
else {
79 label1 = cx_asprintf(
80 "%s/%s",
81 sz_uploaded,
82 sz_total);
83 }
84 ui_set(upload->label_top_left, label1.ptr);
85
86 free(sz_total);
87 free(label1.ptr);
88
89 if (upload->progress.current_file_size >
0) {
90 cxmutstr file_label = cx_asprintf(
"%s (%.0f%%)", upload->current_file_name, ((
float)upload->progress.current_file_transferred/(
float)upload->progress.current_file_size)*
100);
91 ui_set(upload->label_top_right, file_label.ptr);
92 free(file_label.ptr);
93 }
94
95 time_t start = upload->progress.speedtest_start;
96 if(t >= upload->progress.speedtest_start +
4) {
97 uint64_t bytesPerSeconds = dav_transfer_speed(&upload->progress, t);
98 if(start >
0) {
99 char *szps = util_size_str(
FALSE, bytesPerSeconds);
100 cxmutstr label3 = cx_asprintf(
"%s/s", szps);
101 free(szps);
102 ui_set(upload->label_bottom_left, label3.ptr);
103 free(label3.ptr);
104 }
105 }
106 }
107
108
109
110 static int uithr_update_upload_labels(
void *data) {
111 update_upload_labels(data);
112 return 0;
113 }
114
115 static void upload_dav_progress(DavResource *res,
int64_t total,
int64_t now,
void *data) {
116 DavFileUpload *upload = data;
117 if (upload->upload_file) {
118 if (now > upload->progress.current_file_size) {
119
120
121
122 int64_t extra = now - upload->progress.current_file_size;
123 upload->progress.current_file_size += extra;
124 upload->progress.total_bytes += extra;
125 }
126
127 int64_t new_progress = now - upload->progress.current_file_transferred;
128 upload->progress.transferred_bytes += new_progress;
129 upload->progress.current_file_transferred = now;
130
131 ui_call_mainthread(uithr_update_upload_labels, upload);
132 }
133 }
134
135
136 typedef struct FileNameUpdate {
137 DavFileUpload *upload;
138 char *name;
139 char *path;
140 DavBool iscollection;
141 } FileNameUpdate;
142
143 static int uithr_update_file_label(FileNameUpdate *update) {
144 if(update->upload->cancel) {
145 return 0;
146 }
147
148
149 if (update->upload->current_file_name) {
150 free(update->upload->current_file_name);
151 }
152 update->upload->current_file_name = update->name;
153
154 ui_set(update->upload->label_top_right, update->name);
155
156 DavFileUpload *upload = update->upload;
157 DavBrowser *browser = upload->browser;
158
159 if (upload->collection == browser->current && upload->collection_ctn == browser->res_counter) {
160 char *parent = util_parent_path(update->path);
161 cxstring parent_s = cx_str(parent);
162 cxstring colpath_s = cx_str(upload->collection->path);
163 if (parent_s.length >
0 && parent_s.ptr[parent_s.length -
1] ==
'/') {
164 parent_s.length--;
165 }
166 if (colpath_s.length >
0 && colpath_s.ptr[colpath_s.length -
1] ==
'/') {
167 colpath_s.length--;
168 }
169
170
171 if (!cx_strcmp(parent_s, colpath_s)) {
172 DavResource *ui_res = dav_resource_new(upload->collection->session, update->path);
173 ui_res->iscollection = update->iscollection;
174 ui_res->lastmodified = time(
NULL);
175 ui_res->creationdate = time(
NULL);
176 upload->current_resource = ui_res;
177
178 ui_list_append(browser->resources, ui_res);
179 browser->resources->update(browser->resources,
0);
180 }
else {
181 upload->current_resource =
NULL;
182 }
183 free(parent);
184 }
185
186 free(update->path);
187 free(update);
188 return 0;
189 }
190
191 static size_t dufile_read(
void *buf,
size_t size,
size_t count,
void *stream) {
192 DUFile *f = (DUFile*)stream;
193 if(f->upload->cancel) {
194 return 0;
195 }
196 return fread(buf, size, count, f->fd);
197 }
198
199 static int dufile_seek(
const void *stream,
long off,
int whence) {
200 DUFile *f = (DUFile*)stream;
201 return fseek(f->fd, off, whence);
202 }
203
204 static int qthr_file_upload(
void *data) {
205 DUFile *f = data;
206 DavFileUpload *upload = f->upload;
207 DavSession *sn = upload->sn;
208
209 if(upload->cancel) {
210 return 0;
211 }
212
213 FILE *in = sys_fopen(f->path,
"rb");
214 if (!in) {
215
216 return 0;
217 }
218 f->fd = in;
219
220 upload->upload_file =
TRUE;
221 upload->progress.current_file_size = f->bytes;
222 upload->progress.current_file_transferred =
0;
223
224 DavResource *res = dav_resource_new(sn, f->upload_path);
225
226 FileNameUpdate *ui_update = malloc(
sizeof(FileNameUpdate));
227 ui_update->upload = upload;
228 ui_update->name = strdup(res->name);
229 ui_update->path = strdup(res->path);
230 ui_update->iscollection =
FALSE;
231 ui_call_mainthread((ui_threadfunc)uithr_update_file_label, ui_update);
232
233 dav_set_content(res, f, (dav_read_func)dufile_read, (dav_seek_func)dufile_seek);
234 if (dav_store(res)) {
235 f->error = sn->error;
236 }
237 dav_resource_free(res);
238
239 fclose(in);
240
241 upload->upload_file =
FALSE;
242
243 return 0;
244 }
245
246 static void uithr_file_uploaded(UiEvent *event,
void *data) {
247 DUFile *file = data;
248 DavFileUpload *upload = file->upload;
249
250 upload->progress.transferred_files++;
251
252
253 double progress = upload_progress(upload);
254 ui_set(upload->progressbar, upload_progress(upload));
255
256 update_upload_labels(upload);
257
258
259 DavBrowser *browser = upload->browser;
260 if (upload->collection == browser->current && upload->collection_ctn == browser->res_counter) {
261 if (upload->current_resource) {
262 upload->current_resource->contentlength = upload->progress.current_file_transferred;
263 browser->resources->update(browser->resources,
0);
264 }
265 }
266 upload->current_resource =
NULL;
267
268 free(file->path);
269 free(file->upload_path);
270 }
271
272 static int qthr_dir_upload(
void *data) {
273 DUFile *f = data;
274 DavFileUpload *upload = f->upload;
275 DavSession *sn = upload->sn;
276
277 DavResource *res = dav_resource_new(sn, f->upload_path);
278 res->iscollection =
TRUE;
279
280 FileNameUpdate *ui_update = malloc(
sizeof(FileNameUpdate));
281 ui_update->upload = upload;
282 ui_update->name = strdup(res->name);
283 ui_update->path = strdup(res->path);
284 ui_update->iscollection =
TRUE;
285 ui_call_mainthread((ui_threadfunc)uithr_update_file_label, ui_update);
286
287 if (dav_create(res)) {
288 f->error = sn->error;
289 }
290
291 dav_resource_free(res);
292
293 return 0;
294 }
295
296 static void uithr_dir_uploaded(UiEvent *event,
void *data) {
297 DUFile *file = data;
298 DavFileUpload *upload = file->upload;
299
300 upload->progress.transferred_directories++;
301
302 update_upload_labels(upload);
303
304 upload->current_resource =
NULL;
305
306 free(file->path);
307 free(file->upload_path);
308 }
309
310 static int qthr_upload_finished(
void *data) {
311 return 0;
312 }
313
314 static void uithr_upload_finished(UiEvent *event,
void *data) {
315 DavFileUpload *upload = data;
316 if(upload->cancel) {
317 ui_set(upload->label_bottom_left,
"Canceled");
318 }
319 if(upload->dialog->ref >
1) {
320 ui_close(upload->dialog);
321 }
322 ui_object_unref(upload->dialog);
323 }
324
325 static int jobthr_upload_scan(
void *data) {
326 DavFileUpload *upload = data;
327
328 CxList *stack = cxLinkedListCreateSimple(
CX_STORE_POINTERS);
329 for (
int i =
0; i < upload->files.nfiles; i++) {
330 DUFile *f = malloc(
sizeof(DUFile));
331 f->path = strdup(upload->files.files[i]);
332 f->upload_path = util_concat_path(upload->base_path, util_path_file_name(f->path));
333 f->isdirectory =
FALSE;
334 f->bytes =
0;
335 f->upload = upload;
336 f->error =
0;
337 cxListInsert(stack,
0, f);
338 }
339
340 while (cxListSize(stack) >
0 && !upload->cancel) {
341 DUFile *f = cxListAt(stack,
0);
342
343 char *path = util_concat_path(upload->base_path, f->upload_path);
344 cxListRemove(stack,
0);
345
346 SYS_STAT s;
347 if (!sys_stat(f->path, &s)) {
348 if (
S_ISDIR(s.st_mode)) {
349 f->isdirectory =
TRUE;
350 upload->progress.total_directories++;
351 ui_threadpool_job(upload->queue, upload->dialog, qthr_dir_upload, f, uithr_dir_uploaded, f);
352
353 SYS_DIR dir = sys_opendir(f->path);
354 if (dir) {
355 SysDirEnt *entry;
356 int nument =
0;
357 while((entry = sys_readdir(dir)) !=
NULL) {
358 if(!strcmp(entry->name,
".") || !strcmp(entry->name,
"..")) {
359 continue;
360 }
361
362 cxmutstr newpath = util_concat_sys_path(cx_str(f->path), cx_str(entry->name));
363 char *new_upload_path = util_concat_path(f->upload_path, entry->name);
364
365 DUFile *child = malloc(
sizeof(DUFile));
366 child->path = newpath.ptr;
367 child->upload_path = new_upload_path;
368 child->isdirectory =
FALSE;
369 child->bytes =
0;
370 child->upload = upload;
371 child->error =
0;
372 cxListAdd(stack, child);
373 }
374
375 sys_closedir(dir);
376 }
377 }
else if (
S_ISREG(s.st_mode)) {
378 f->isdirectory =
FALSE;
379 f->bytes = s.st_size;
380 upload->progress.total_files++;
381 upload->progress.total_bytes += s.st_size;
382 ui_threadpool_job(upload->queue, upload->dialog, qthr_file_upload, f, uithr_file_uploaded, f);
383 }
384 }
else {
385
386
387 }
388 }
389
390 ui_threadpool_job(upload->queue, upload->dialog, qthr_upload_finished, upload, uithr_upload_finished, upload);
391
392 ui_filelist_free(upload->files);
393
394 return 0;
395 }
396
397 static void uithr_upload_scan_finished(UiEvent *event,
void *data) {
398 DavFileUpload *upload = data;
399
400 update_upload_labels(upload);
401 }
402
403 static void upload_window_closed(UiEvent *event,
void *data) {
404 DavFileUpload *upload = event->window;
405 ui_threadpool_destroy(upload->queue);
406
407 dav_session_destroy(upload->sn);
408 }
409
410 void action_upload_cancel(UiEvent *event,
void *data) {
411 DavFileUpload *upload = event->window;
412 if(!upload->cancel) {
413 ui_set(upload->label_bottom_left,
"Cancel...");
414 upload->cancel =
TRUE;
415 }
416 }
417
418 static void dav_file_upload_cleanup(DavFileUpload *upload) {
419 application_remove_transfer(&upload->trans);
420 ui_object_unref(upload->browser->window);
421 }
422
423 DavFileUpload* dav_upload_create(DavBrowser *browser, UiObject *obj, UiFileList files) {
424 UiContext *ctx = obj->ctx;
425 CxMempool *mp = ui_cx_mempool(ctx);
426 DavFileUpload *upload = ui_malloc(ctx,
sizeof(DavFileUpload));
427 memset(upload,
0,
sizeof(DavFileUpload));
428 upload->dialog = obj;
429 obj->window = upload;
430 ui_object_ref(obj);
431 ui_object_ref(browser->window);
432
433 size_t label_len = strlen(util_resource_name(files.files[
0])) +
16;
434 upload->trans.label = cxCalloc(mp->allocator, label_len,
1);
435 upload->trans.label_len = snprintf(upload->trans.label, label_len,
"> %s%s", util_resource_name(files.files[
0]), files.nfiles >
1 ?
" ..." :
"");
436 upload->trans.window = obj;
437
438 upload->progressbar = ui_double_new(ctx,
"progressbar");
439 upload->label_top_left = ui_string_new(ctx,
"label_top_left");
440 upload->label_top_right = ui_string_new(ctx,
"label_top_right");
441 upload->label_bottom_left = ui_string_new(ctx,
"label_bottom_left");
442 upload->label_bottom_right = ui_string_new(ctx,
"label_bottom_right");
443
444
445
446 DavSession *upload_session = dav_session_clone(browser->sn);
447
448 dav_session_set_progresscallback(upload_session,
NULL, upload_dav_progress, upload);
449
450 upload->browser = browser;
451 upload->sn = upload_session;
452 upload->files = files;
453 upload->base_path = ui_strdup(ctx, browser->current->path);
454 upload->queue = ui_threadpool_create(
1);
455
456 upload->collection = browser->current;
457 upload->collection_ctn = browser->res_counter;
458
459 cxMempoolRegister(mp, upload_session, (cx_destructor_func)dav_session_destroy);
460 cxMempoolRegister(mp, upload->queue, (cx_destructor_func)ui_threadpool_destroy);
461 cxMempoolSetDestructor(upload, (cx_destructor_func)dav_file_upload_cleanup);
462
463 ui_set(upload->label_top_left,
"");
464 ui_set(upload->label_top_right,
"");
465 ui_set(upload->label_bottom_left,
"");
466 ui_set(upload->label_bottom_right,
"");
467 ui_set(upload->progressbar,
0);
468
469 return upload;
470 }
471
472 void dav_upload_start(DavFileUpload *upload) {
473 ui_show(upload->dialog);
474
475
476 ui_job(upload->dialog, jobthr_upload_scan, upload, uithr_upload_scan_finished, upload);
477 }
478