summaryrefslogtreecommitdiff
path: root/src/modules/ecordova/linux
diff options
context:
space:
mode:
authorFelipe Magno de Almeida <felipe@expertisesolutions.com.br>2015-10-29 17:06:29 -0200
committerFelipe Magno de Almeida <felipe@expertisesolutions.com.br>2015-10-29 17:06:29 -0200
commit308b29c3203d711474f1e7cd6b61ae96827d3e5e (patch)
tree4d36aa90a6e44620a8cfe30264d1ac0d5e3f1176 /src/modules/ecordova/linux
parent74f70e020995860f8427633b5872c70ed27e0c0d (diff)
ecordova: Moved to tizen modules
Diffstat (limited to 'src/modules/ecordova/linux')
-rw-r--r--src/modules/ecordova/linux/ecordova_filetransfer.c647
-rw-r--r--src/modules/ecordova/linux/ecordova_filetransfer_private.h21
2 files changed, 668 insertions, 0 deletions
diff --git a/src/modules/ecordova/linux/ecordova_filetransfer.c b/src/modules/ecordova/linux/ecordova_filetransfer.c
new file mode 100644
index 0000000000..72bb4f040b
--- /dev/null
+++ b/src/modules/ecordova/linux/ecordova_filetransfer.c
@@ -0,0 +1,647 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include "ecordova_filetransfer_private.h"
6#include "ecordova_directoryentry_private.h"
7
8#include <Ecore_Con.h>
9
10#ifdef _WIN32
11# ifdef DLL_EXPORT
12# define EAPI __declspec(dllexport)
13# else
14# define EAPI
15# endif /* ! DLL_EXPORT */
16#else
17# ifdef __GNUC__
18# if __GNUC__ >= 4
19# define EAPI __attribute__ ((visibility("default")))
20# else
21# define EAPI
22# endif
23# else
24# define EAPI
25# endif
26#endif /* ! _WIN32 */
27
28/* logging support */
29extern int _ecordova_log_dom;
30
31#define CRI(...) EINA_LOG_DOM_CRIT(_ecordova_log_dom, __VA_ARGS__)
32#define ERR(...) EINA_LOG_DOM_ERR(_ecordova_log_dom, __VA_ARGS__)
33#define WRN(...) EINA_LOG_DOM_WARN(_ecordova_log_dom, __VA_ARGS__)
34#define INF(...) EINA_LOG_DOM_INFO(_ecordova_log_dom, __VA_ARGS__)
35#define DBG(...) EINA_LOG_DOM_DBG(_ecordova_log_dom, __VA_ARGS__)
36
37#define MY_CLASS ECORDOVA_FILETRANSFER_CLASS
38#define MY_CLASS_NAME "Ecordova_FileTransfer"
39
40struct _Ecordova_FileTransfer_Job
41{
42 char *source;
43 char *target;
44 Ecore_File_Download_Job *download;
45 Ecore_Thread *upload;
46 int upload_error;
47 char *upload_buffer;
48 long int upload_length;
49 Ecore_Con_Url *upload_con_url;
50 Ecore_Event_Handler *progress_event_hanbler;
51 Ecore_Event_Handler *complete_event_hanbler;
52 Ecordova_FileTransfer_UploadOptions upload_options;
53};
54
55static int _download_progress_cb(void *, const char *, long int, long int, long int, long int);
56static void _download_completion_cb(void *, const char *, int);
57static void _clear(Ecordova_FileTransfer_Data *);
58static void _abort_error_notify(Ecordova_FileTransfer_Data *);
59static void _status_error_notify(Ecordova_FileTransfer_Data *, int);
60static void _file_error_notify(Ecordova_FileTransfer_Data *, int);
61static void _connection_error_notify(Ecordova_FileTransfer_Data *);
62static void _already_in_progress_error_notify(Ecordova_FileTransfer_Data *, const char *, const char *);
63static void _upload_cb(void *, Ecore_Thread *);
64static void _upload_progress_notify(size_t, size_t, Eo *, Ecore_Thread *);
65static void _upload_progress_cb(void *, Ecore_Thread *, void *);
66static void _upload_end_cb(void *, Ecore_Thread *);
67static void _upload_abort_cb(void *, Ecore_Thread *);
68static void _progress_notify(Ecordova_FileTransfer_Data *, Ecordova_ProgressEvent *);
69static Ecordova_FileTransfer_Job *_job_new(const char *, const char *);
70static void _job_free(Ecordova_FileTransfer_Job **);
71static Eina_Bool _url_progress_cb(void *, int, void *);
72static Eina_Bool _url_complete_cb(void *, int, void *);
73
74static Eo_Base *
75_ecordova_filetransfer_eo_base_constructor(Eo *obj,
76 Ecordova_FileTransfer_Data *pd)
77{
78 DBG("(%p)", obj);
79
80 pd->obj = obj;
81 pd->job = NULL;
82
83 return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
84}
85
86static void
87_ecordova_filetransfer_constructor(Eo *obj EINA_UNUSED,
88 Ecordova_FileTransfer_Data *pd EINA_UNUSED)
89{
90 DBG("(%p)", obj);
91}
92
93static void
94_ecordova_filetransfer_eo_base_destructor(Eo *obj,
95 Ecordova_FileTransfer_Data *pd)
96{
97 DBG("(%p)", obj);
98
99 _clear(pd);
100
101 eo_do_super(obj, MY_CLASS, eo_destructor());
102}
103
104static void
105_ecordova_filetransfer_upload(Eo *obj EINA_UNUSED,
106 Ecordova_FileTransfer_Data *pd EINA_UNUSED,
107 const char *file_url EINA_UNUSED,
108 const char *server,
109 Ecordova_FileTransfer_UploadOptions *options EINA_UNUSED,
110 Eina_Bool trust_all_hosts EINA_UNUSED)
111{
112 DBG("(%p)", obj);
113 EINA_SAFETY_ON_NULL_RETURN(file_url);
114 EINA_SAFETY_ON_NULL_RETURN(server);
115
116 if (pd->job)
117 {
118 _already_in_progress_error_notify(pd, file_url, server);
119 return;
120 }
121
122 bool is_http = strncmp(server, "http://", 7) == 0;
123 bool is_https = strncmp(server, "https://", 8) == 0;
124
125 if (!is_http && !is_https)
126 {
127 ERR("%s", "Invalid server address");
128 Ecordova_FileTransfer_Error error = {
129 .code = ECORDOVA_FILETRANSFER_ERRORCODE_INVALID_URL_ERR,
130 .source = file_url,
131 .target = server,
132 .http_status = 0,
133 .body = NULL,
134 .exception = "Invalid server address"
135 };
136 eo_do(pd->obj,
137 eo_event_callback_call(ECORDOVA_FILETRANSFER_EVENT_ERROR, &error));
138 return;
139 }
140
141 pd->job = _job_new(file_url, server);
142 pd->job->upload = ecore_thread_feedback_run(_upload_cb,
143 _upload_progress_cb,
144 _upload_end_cb,
145 _upload_abort_cb,
146 pd,
147 EINA_FALSE);
148}
149
150static void
151_ecordova_filetransfer_download(Eo *obj,
152 Ecordova_FileTransfer_Data *pd,
153 const char *source,
154 const char *target,
155 Eina_Bool trust_all_hosts EINA_UNUSED,
156 Eina_Hash *options)
157{
158 DBG("(%p)", obj);
159 EINA_SAFETY_ON_NULL_RETURN(source);
160 EINA_SAFETY_ON_NULL_RETURN(target);
161
162 if (pd->job)
163 {
164 _already_in_progress_error_notify(pd, source, target);
165 return;
166 }
167
168 Ecordova_FileTransfer_Job *job = _job_new(source, target);
169
170 Eina_Bool ret;
171 if (options)
172 ret = ecore_file_download_full(source,
173 target,
174 _download_completion_cb,
175 _download_progress_cb,
176 pd,
177 &job->download,
178 options);
179 else
180 ret = ecore_file_download(source,
181 target,
182 _download_completion_cb,
183 _download_progress_cb,
184 pd,
185 &job->download);
186
187 if (!ret)
188 {
189 _job_free(&job);
190 ERR("%s", "An error occurred downloading the file");
191 Ecordova_FileTransfer_Error error = {
192 .code = ECORDOVA_FILETRANSFER_ERRORCODE_ABORT_ERR,
193 .source = source,
194 .target = target,
195 .http_status = 0,
196 .body = NULL,
197 .exception = "An error occurred downloading the file"
198 };
199 eo_do(obj, eo_event_callback_call(ECORDOVA_FILETRANSFER_EVENT_ERROR, &error));
200 return;
201 }
202
203 pd->job = job;
204}
205
206static void
207_ecordova_filetransfer_abort(Eo *obj, Ecordova_FileTransfer_Data *pd)
208{
209 DBG("(%p)", obj);
210
211 if (!pd->job) return;
212
213 if (pd->job->download)
214 ecore_file_download_abort(pd->job->download);
215 else
216 ecore_thread_cancel(pd->job->upload);
217}
218
219static int
220_download_progress_cb(void *data,
221 const char *file EINA_UNUSED,
222 long int dltotal,
223 long int dlnow,
224 long int ultotal EINA_UNUSED,
225 long int ulnow EINA_UNUSED)
226{
227 Ecordova_FileTransfer_Data *pd = data;
228 DBG("(%p)", pd->obj);
229 Ecordova_ProgressEvent event = {
230 .type = "download",
231 .cancelable = true,
232 .length_computable = true,
233 .loaded = dlnow,
234 .total = dltotal,
235 .target = pd->obj
236 };
237 _progress_notify(pd, &event);
238 return ECORE_FILE_PROGRESS_CONTINUE;
239}
240
241static void
242_download_completion_cb(void *data, const char *file, int status)
243{
244 Ecordova_FileTransfer_Data *pd = data;
245 DBG("(%p)", pd->obj);
246 if (1 == status)
247 _abort_error_notify(pd);
248 else if (200 != status)
249 _status_error_notify(pd, status);
250 else
251 {
252 char *path, *name, *native;
253 split_path(NULL, file, &path, &name, &native);
254
255 Ecordova_FileEntry *file_entry = eo_add(ECORDOVA_FILEENTRY_CLASS, NULL,
256 ecordova_fileentry_constructor(name, path, NULL, native)); // TODO: filesystem?
257 eo_do(pd->obj,
258 eo_event_callback_call(ECORDOVA_FILETRANSFER_EVENT_DOWNLOAD_SUCCESS, file_entry));
259 eo_unref(file_entry);
260
261 free(path);
262 free(name);
263 free(native);
264 }
265
266 _clear(pd);
267}
268
269static void
270_clear(Ecordova_FileTransfer_Data *pd)
271{
272 DBG("(%p)", pd->obj);
273 _job_free(&pd->job);
274}
275
276static void
277_upload_cb(void *data, Ecore_Thread *thread)
278{
279 Ecordova_FileTransfer_Data *pd = data;
280 DBG("(%p)", pd->obj);
281
282 if (ecore_thread_check(thread))
283 {
284 pd->job->upload_error = 1;
285 return;
286 }
287
288 FILE *stream = fopen(pd->job->source, "rb");
289 if (!stream)
290 {
291 pd->job->upload_error = errno;
292 return;
293 }
294
295 int error = fseek(stream, 0L, SEEK_END);
296 if (error)
297 {
298 pd->job->upload_error = errno;
299 goto on_error;
300 }
301
302 pd->job->upload_length = ftell(stream);
303 if (pd->job->upload_length < 0)
304 {
305 pd->job->upload_error = errno;
306 goto on_error;
307 }
308
309 error = fseek(stream, 0L, SEEK_SET);
310 {
311 pd->job->upload_error = errno;
312 goto on_error;
313 }
314
315 _upload_progress_notify(0, pd->job->upload_length, pd->obj, thread);
316
317 pd->job->upload_buffer = malloc(pd->job->upload_length);
318 if (!pd->job->upload_buffer)
319 {
320 pd->job->upload_error = errno;
321 goto on_error;
322 }
323
324 long int total_read = 0;
325 while (total_read < pd->job->upload_length)
326 {
327 size_t read = fread(&pd->job->upload_buffer[total_read],
328 sizeof(char),
329 pd->job->upload_length - total_read,
330 stream);
331 total_read += read;
332
333 _upload_progress_notify(0, pd->job->upload_length, pd->obj, thread);
334 if (ecore_thread_check(thread))
335 {
336 pd->job->upload_error = 1;
337 break;
338 }
339 }
340
341on_error:
342 fclose(stream);
343}
344
345static void
346_upload_progress_notify(size_t uploaded,
347 size_t total,
348 Eo *obj,
349 Ecore_Thread *thread)
350{
351 DBG("(%p)", obj);
352
353 Ecordova_ProgressEvent *progress = malloc(sizeof(Ecordova_ProgressEvent));
354 *progress = (Ecordova_ProgressEvent)
355 {
356 .type = "upload",
357 .length_computable = EINA_TRUE,
358 .loaded = uploaded,
359 .total = total,
360 .target = obj
361 };
362 if (!ecore_thread_feedback(thread, progress))
363 free(progress);
364}
365
366static void
367_upload_progress_cb(void *data,
368 Ecore_Thread *thread EINA_UNUSED,
369 void *msg_data)
370{
371 Ecordova_FileTransfer_Data *pd = data;
372 DBG("(%p)", pd->obj);
373 Ecordova_ProgressEvent *event = msg_data;
374 _progress_notify(pd, event);
375 free(event);
376}
377
378static void
379_upload_end_cb(void *data, Ecore_Thread *thread EINA_UNUSED)
380{
381 Ecordova_FileTransfer_Data *pd = data;
382 DBG("(%p)", pd->obj);
383
384 if (1 == pd->job->upload_error)
385 _abort_error_notify(pd);
386 else if (pd->job->upload_error)
387 _file_error_notify(pd, pd->job->upload_error);
388 else
389 {
390 pd->job->upload_con_url = ecore_con_url_custom_new(pd->job->target,
391 pd->job->upload_options.http_method);
392 if (!pd->job->upload_con_url)
393 {
394 _connection_error_notify(pd);
395 goto on_error;
396 }
397
398 pd->job->complete_event_hanbler = ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE, _url_complete_cb, pd);
399 pd->job->progress_event_hanbler = ecore_event_handler_add(ECORE_CON_EVENT_URL_PROGRESS, _url_progress_cb, pd);
400 if (!pd->job->complete_event_hanbler || !pd->job->progress_event_hanbler)
401 {
402 _connection_error_notify(pd);
403 goto on_error;
404 }
405
406 if (pd->job->upload_options.headers)
407 {
408 Eina_Iterator *it = eina_hash_iterator_tuple_new(pd->job->upload_options.headers);
409 Eina_Hash_Tuple *tuple;
410 EINA_ITERATOR_FOREACH(it, tuple)
411 ecore_con_url_additional_header_add(pd->job->upload_con_url, tuple->key, tuple->data);
412 eina_iterator_free(it);
413 }
414
415 Eina_Bool ret = ecore_con_url_post(pd->job->upload_con_url,
416 pd->job->upload_buffer,
417 pd->job->upload_length,
418 pd->job->upload_options.mime_type);
419 if (!ret)
420 {
421 _connection_error_notify(pd);
422 goto on_error;
423 }
424
425 return;
426 }
427
428on_error:
429 _clear(pd);
430}
431
432static void
433_upload_abort_cb(void *data, Ecore_Thread *thread EINA_UNUSED)
434{
435 Ecordova_FileTransfer_Data *pd = data;
436 DBG("(%p)", pd->obj);
437
438 _abort_error_notify(pd);
439 _clear(pd);
440}
441
442static void
443_progress_notify(Ecordova_FileTransfer_Data *pd,
444 Ecordova_ProgressEvent *event)
445{
446 eo_do(pd->obj,
447 eo_event_callback_call(ECORDOVA_FILETRANSFER_EVENT_ON_PROGRESS, event));
448}
449
450static Ecordova_FileTransfer_Job *
451_job_new(const char *source, const char *target)
452{
453 Ecordova_FileTransfer_Job *job = calloc(1, sizeof(Ecordova_FileTransfer_Job));
454 job->source = strdup(source);
455 job->target = strdup(target);
456 job->upload_options = (Ecordova_FileTransfer_UploadOptions){
457 .file_key = "file",
458 .file_name = "image.jpg",
459 .http_method = "POST",
460 .mime_type = "image/jpeg",
461 .chunked_mode = EINA_TRUE
462 };
463 return job;
464}
465
466static void
467_job_free(Ecordova_FileTransfer_Job **job)
468{
469 if (!*job) return;
470
471 if ((*job)->upload_con_url)
472 {
473 if ((*job)->progress_event_hanbler)
474 ecore_event_handler_del((*job)->progress_event_hanbler);
475 if ((*job)->complete_event_hanbler)
476 ecore_event_handler_del((*job)->complete_event_hanbler);
477 ecore_con_url_free((*job)->upload_con_url);
478 }
479 free((*job)->upload_buffer);
480 free((*job)->source);
481 free((*job)->target);
482 free(*job);
483 *job = NULL;
484}
485
486static Eina_Bool
487_url_progress_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event_info)
488{
489 Ecore_Con_Event_Url_Progress *url_progress = event_info;
490 Ecordova_FileTransfer_Data *pd = data;
491
492 Ecordova_ProgressEvent event = {
493 .type = "upload",
494 .cancelable = false,
495 .length_computable = true,
496 .loaded = url_progress->up.now,
497 .total = url_progress->up.total,
498 .target = pd->obj
499 };
500 _progress_notify(pd, &event);
501
502 return EINA_TRUE;
503}
504
505static Eina_Bool
506_url_complete_cb(void *data, int type EINA_UNUSED, void *event_info)
507{
508 Ecore_Con_Event_Url_Complete *url_complete = event_info;
509 Ecordova_FileTransfer_Data *pd = data;
510
511 if (200 != url_complete->status)
512 _status_error_notify(pd, url_complete->status);
513 else
514 {
515 Eina_Hash *headers_hash = NULL;
516 const Eina_List *headers = ecore_con_url_response_headers_get(url_complete->url_con);
517 if (eina_list_count(headers))
518 {
519 headers_hash = eina_hash_string_superfast_new(free);
520 const char *header_line;
521 const Eina_List *it;
522 EINA_LIST_FOREACH(headers, it, header_line)
523 {
524 const char *separator = strchr(header_line, ':');
525 if (!separator) continue;
526
527 size_t key_len = separator - header_line + 1;
528 char key[key_len];
529 strncpy(key, header_line, key_len);
530 key[key_len - 1] = '\0';
531
532 if (*(++separator) == ' ')
533 ++separator;
534 char *value = strdup(separator);
535 eina_hash_add(headers_hash, key, value);
536 }
537 }
538
539 Ecordova_FileTransfer_UploadResult result = {
540 .bytes_sent = pd->job->upload_length,
541 .response_code = url_complete->status,
542 .headers = headers_hash,
543 .response = NULL // TODO: Get the HTTP response
544 };
545 eo_do(pd->obj,
546 eo_event_callback_call(ECORDOVA_FILETRANSFER_EVENT_UPLOAD_SUCCESS,
547 &result));
548 if (headers_hash)
549 eina_hash_free(headers_hash);
550 }
551
552 _clear(pd);
553 return EINA_TRUE;
554}
555
556static void
557_abort_error_notify(Ecordova_FileTransfer_Data *pd)
558{
559 INF("%s", "Aborted");
560 Ecordova_FileTransfer_Error error = {
561 .code = ECORDOVA_FILETRANSFER_ERRORCODE_ABORT_ERR,
562 .source = pd->job->source,
563 .target = pd->job->target,
564 .http_status = 0,
565 .body = NULL,
566 .exception = "Aborted"
567 };
568 eo_do(pd->obj,
569 eo_event_callback_call(ECORDOVA_FILETRANSFER_EVENT_ERROR, &error));
570}
571
572static void
573_status_error_notify(Ecordova_FileTransfer_Data *pd, int status)
574{
575 ERR("Error status: %d", status);
576 Ecordova_FileTransfer_Error error = {
577 // TODO: translate other errors checking first which protocol it is.
578 .code = 404 == status ? ECORDOVA_FILETRANSFER_ERRORCODE_FILE_NOT_FOUND_ERR :
579 ECORDOVA_FILETRANSFER_ERRORCODE_ABORT_ERR,
580 .source = pd->job->source,
581 .target = pd->job->target,
582 .http_status = status,
583 .body = NULL,
584 .exception = "Error"
585 };
586 eo_do(pd->obj,
587 eo_event_callback_call(ECORDOVA_FILETRANSFER_EVENT_ERROR, &error));
588}
589
590static void
591_file_error_notify(Ecordova_FileTransfer_Data *pd, int code)
592{
593 ERR("Error code: %d", code);
594 Ecordova_FileTransfer_Error error = {
595 .code = ECORDOVA_FILETRANSFER_ERRORCODE_FILE_NOT_FOUND_ERR,
596 .source = pd->job->source,
597 .target = pd->job->target,
598 .http_status = 0,
599 .body = NULL,
600 .exception = "Internal error"
601 };
602 eo_do(pd->obj,
603 eo_event_callback_call(ECORDOVA_FILETRANSFER_EVENT_ERROR, &error));
604}
605
606static void
607_connection_error_notify(Ecordova_FileTransfer_Data *pd)
608{
609 ERR("%s", "Connection error");
610 Ecordova_FileTransfer_Error error = {
611 .code = ECORDOVA_FILETRANSFER_ERRORCODE_CONNECTION_ERR,
612 .source = pd->job->source,
613 .target = pd->job->target,
614 .http_status = 0,
615 .body = NULL,
616 .exception = "Connection error"
617 };
618 eo_do(pd->obj,
619 eo_event_callback_call(ECORDOVA_FILETRANSFER_EVENT_ERROR, &error));
620}
621
622static void
623_already_in_progress_error_notify(Ecordova_FileTransfer_Data *pd,
624 const char *source,
625 const char *target)
626{
627 ERR("%s", "A job is already in progress");
628 Ecordova_FileTransfer_Error error = {
629 .code = ECORDOVA_FILETRANSFER_ERRORCODE_ABORT_ERR,
630 .source = source,
631 .target = target,
632 .http_status = 0,
633 .body = NULL,
634 .exception = "A job is already in progress"
635 };
636 eo_do(pd->obj,
637 eo_event_callback_call(ECORDOVA_FILETRANSFER_EVENT_ERROR, &error));
638}
639
640#undef EOAPI
641#define EOAPI EAPI
642
643#include "undefs.h"
644
645#define ecordova_filetransfer_class_get ecordova_filetransfer_impl_class_get
646
647#include "ecordova_filetransfer.eo.c"
diff --git a/src/modules/ecordova/linux/ecordova_filetransfer_private.h b/src/modules/ecordova/linux/ecordova_filetransfer_private.h
new file mode 100644
index 0000000000..b17fe85e9a
--- /dev/null
+++ b/src/modules/ecordova/linux/ecordova_filetransfer_private.h
@@ -0,0 +1,21 @@
1#ifndef _ECORDOVA_FILETRANSFER_PRIVATE_H
2#define _ECORDOVA_FILETRANSFER_PRIVATE_H
3
4#include "ecordova_private.h"
5
6#include <Ecore_File.h>
7
8typedef struct _Ecordova_FileTransfer_Data Ecordova_FileTransfer_Data;
9
10typedef struct _Ecordova_FileTransfer_Job Ecordova_FileTransfer_Job;
11
12/**
13 * Ecordova.FileTransfer private data
14 */
15struct _Ecordova_FileTransfer_Data
16{
17 Eo *obj;
18 Ecordova_FileTransfer_Job *job;
19};
20
21#endif