aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/ecore/src/lib/ecore_file/ecore_file_download.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/ecore/src/lib/ecore_file/ecore_file_download.c')
-rw-r--r--libraries/ecore/src/lib/ecore_file/ecore_file_download.c449
1 files changed, 0 insertions, 449 deletions
diff --git a/libraries/ecore/src/lib/ecore_file/ecore_file_download.c b/libraries/ecore/src/lib/ecore_file/ecore_file_download.c
deleted file mode 100644
index 971493e..0000000
--- a/libraries/ecore/src/lib/ecore_file/ecore_file_download.c
+++ /dev/null
@@ -1,449 +0,0 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include <stdlib.h>
6#include <stdio.h>
7#include <string.h>
8
9#ifdef BUILD_ECORE_CON
10# include "Ecore_Con.h"
11#endif
12
13#include "ecore_file_private.h"
14
15#ifdef BUILD_ECORE_CON
16
17#define ECORE_MAGIC_FILE_DOWNLOAD_JOB 0xf7427cb8
18#define ECORE_FILE_DOWNLOAD_TIMEOUT 30
19
20struct _Ecore_File_Download_Job
21{
22 ECORE_MAGIC;
23
24 Ecore_Con_Url *url_con;
25 FILE *file;
26
27 char *dst;
28
29 Ecore_File_Download_Completion_Cb completion_cb;
30 Ecore_File_Download_Progress_Cb progress_cb;
31};
32
33#ifdef HAVE_CURL
34Ecore_File_Download_Job *_ecore_file_download_curl(const char *url, const char *dst,
35 Ecore_File_Download_Completion_Cb completion_cb,
36 Ecore_File_Download_Progress_Cb progress_cb,
37 void *data,
38 Eina_Hash *headers);
39
40static Eina_Bool _ecore_file_download_url_complete_cb(void *data, int type, void *event);
41static Eina_Bool _ecore_file_download_url_progress_cb(void *data, int type, void *event);
42#endif
43
44static Ecore_Event_Handler *_url_complete_handler = NULL;
45static Ecore_Event_Handler *_url_progress_download = NULL;
46static Eina_List *_job_list;
47
48static int download_init = 0;
49
50#endif /* BUILD_ECORE_CON */
51
52int
53ecore_file_download_init(void)
54{
55#ifdef BUILD_ECORE_CON
56 download_init++;
57 if (download_init > 1) return 1;
58 if (!ecore_con_init()) return 0;
59 if (!ecore_con_url_init())
60 {
61 ecore_con_shutdown();
62 return 0;
63 }
64# ifdef HAVE_CURL
65 _url_complete_handler = ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE, _ecore_file_download_url_complete_cb, NULL);
66 _url_progress_download = ecore_event_handler_add(ECORE_CON_EVENT_URL_PROGRESS, _ecore_file_download_url_progress_cb, NULL);
67# endif
68#endif /* BUILD_ECORE_CON */
69 return 1;
70}
71
72void
73ecore_file_download_shutdown(void)
74{
75#ifdef BUILD_ECORE_CON
76 download_init--;
77 if (download_init > 0) return;
78 if (_url_complete_handler)
79 ecore_event_handler_del(_url_complete_handler);
80 if (_url_progress_download)
81 ecore_event_handler_del(_url_progress_download);
82 _url_complete_handler = NULL;
83 _url_progress_download = NULL;
84 ecore_file_download_abort_all();
85 ecore_con_url_shutdown();
86 ecore_con_shutdown();
87#endif /* BUILD_ECORE_CON */
88}
89
90#ifdef BUILD_ECORE_CON
91# ifdef HAVE_CURL
92static Eina_Bool
93_ecore_file_download_headers_foreach_cb(const Eina_Hash *hash __UNUSED__, const void *key, void *data, void *fdata)
94{
95 Ecore_File_Download_Job *job = fdata;
96 ecore_con_url_additional_header_add(job->url_con, key, data);
97
98 return EINA_TRUE;
99}
100# endif
101#endif
102
103static Eina_Bool
104_ecore_file_download(const char *url,
105 const char *dst,
106 Ecore_File_Download_Completion_Cb completion_cb,
107 Ecore_File_Download_Progress_Cb progress_cb,
108 void *data,
109 Ecore_File_Download_Job **job_ret,
110 Eina_Hash *headers)
111{
112#ifdef BUILD_ECORE_CON
113 char *dir = ecore_file_dir_get(dst);
114
115 if (!ecore_file_is_dir(dir))
116 {
117 ERR("%s is not a directory", dir);
118 free(dir);
119 return EINA_FALSE;
120 }
121 free(dir);
122 if (ecore_file_exists(dst))
123 {
124 WRN("%s already exists", dst);
125 return EINA_FALSE;
126 }
127
128 if (!strncmp(url, "file://", 7))
129 {
130 /* FIXME: Maybe fork? Might take a while to copy.
131 * Check filesize? */
132 /* Just copy it */
133
134 url += 7;
135 /* skip hostname */
136 url = strchr(url, '/');
137 return ecore_file_cp(url, dst);
138 }
139# ifdef HAVE_CURL
140 else if ((!strncmp(url, "http://", 7)) || (!strncmp(url, "https://", 8)) ||
141 (!strncmp(url, "ftp://", 6)))
142 {
143 /* download */
144 Ecore_File_Download_Job *job;
145
146 job = _ecore_file_download_curl(url, dst, completion_cb, progress_cb, data, headers);
147 if(job_ret) *job_ret = job;
148 if(job)
149 return EINA_TRUE;
150 else
151 {
152 ERR("no job returned\n");
153 return EINA_FALSE;
154 }
155 return job ? EINA_TRUE : EINA_FALSE;
156 }
157# else
158 else if ((!strncmp(url, "http://", 7)) || (!strncmp(url, "https://", 8)) ||
159 (!strncmp(url, "ftp://", 6)))
160 {
161 (void)completion_cb;
162 (void)progress_cb;
163 (void)data;
164 (void)job_ret;
165 (void)headers;
166 return EINA_FALSE;
167 }
168# endif
169 else
170 {
171 return EINA_FALSE;
172 }
173#else
174 (void)url;
175 (void)dst;
176 (void)completion_cb;
177 (void)progress_cb;
178 (void)data;
179 (void)job_ret;
180 (void)headers;
181 return EINA_FALSE;
182#endif /* BUILD_ECORE_CON */
183}
184
185/**
186 * @addtogroup Ecore_File_Group Ecore_File - Files and directories convenience functions
187 *
188 * @{
189 */
190
191/**
192 * @brief Download the given url to the given destination.
193 *
194 * @param url The complete url to download.
195 * @param dst The local file to save the downloaded to.
196 * @param completion_cb A callback called on download complete.
197 * @param progress_cb A callback called during the download operation.
198 * @param data User data passed to both callbacks.
199 * @param job_ret Job used to abort the download.
200 * @return EINA_TRUE if the download start or EINA_FALSE on failure
201 *
202 * This function starts the download of the URL @p url and saves it to
203 * @p dst. @p url must provide the protocol, including 'http://',
204 * 'ftp://' or 'file://'. Ecore_File must be compiled with CURL to
205 * download using http and ftp protocols. If @p dst is ill-formed, or
206 * if it already exists, the function returns EINA_FALSE. When the
207 * download is complete, the callback @p completion_cb is called and
208 * @p data is passed to it. The @p status parameter of @p completion_cb
209 * will be filled with the status of the download (200, 404,...). The
210 * @p progress_cb is called during the download operation, each time a
211 * packet is received or when CURL wants. It can be used to display the
212 * percentage of the downloaded file. Return 0 from this callback, if provided,
213 * to continue the operation or anything else to abort the download. The only
214 * operations that can be aborted are those with protocol 'http' or 'ftp'. In
215 * that case @p job_ret can be filled. It can be used with
216 * ecore_file_download_abort() or ecore_file_download_abort_all() to
217 * respectively abort one or all download operations. This function returns
218 * EINA_TRUE if the download starts, EINA_FALSE otherwise.
219 */
220EAPI Eina_Bool
221ecore_file_download(const char *url,
222 const char *dst,
223 Ecore_File_Download_Completion_Cb completion_cb,
224 Ecore_File_Download_Progress_Cb progress_cb,
225 void *data,
226 Ecore_File_Download_Job **job_ret)
227{
228 return _ecore_file_download(url, dst, completion_cb, progress_cb, data, job_ret, NULL);
229}
230
231/**
232 * @brief Download the given url to the given destination with additional headers.
233 *
234 * @param url The complete url to download.
235 * @param dst The local file to save the downloaded to.
236 * @param completion_cb A callback called on download complete.
237 * @param progress_cb A callback called during the download operation.
238 * @param data User data passed to both callbacks.
239 * @param job_ret Job used to abort the download.
240 * @param headers pointer of header lists.
241 * @return EINA_TRUE if the download start or EINA_FALSE on failure
242 */
243EAPI Eina_Bool
244ecore_file_download_full(const char *url,
245 const char *dst,
246 Ecore_File_Download_Completion_Cb completion_cb,
247 Ecore_File_Download_Progress_Cb progress_cb,
248 void *data,
249 Ecore_File_Download_Job **job_ret,
250 Eina_Hash *headers)
251{
252 return _ecore_file_download(url, dst, completion_cb, progress_cb, data, job_ret, headers);
253}
254
255/**
256 * @brief Check if the given protocol is available.
257 *
258 * @param protocol The protocol to check.
259 * @return EINA_TRUE if protocol is handled, EINA_FALSE otherwise.
260 *
261 * This function returns EINA_TRUE if @p protocol is supported,
262 * EINA_FALSE otherwise. @p protocol can be 'http://', 'ftp://' or
263 * 'file://'. Ecore_FILE must be compiled with CURL to handle http and
264 * ftp protocols.
265 */
266EAPI Eina_Bool
267ecore_file_download_protocol_available(const char *protocol)
268{
269#ifdef BUILD_ECORE_CON
270 if (!strncmp(protocol, "file://", 7)) return EINA_TRUE;
271# ifdef HAVE_CURL
272 else if (!strncmp(protocol, "http://", 7)) return EINA_TRUE;
273 else if (!strncmp(protocol, "ftp://", 6)) return EINA_TRUE;
274# endif
275#else
276 (void)protocol;
277#endif /* BUILD_ECORE_CON */
278
279 return EINA_FALSE;
280}
281
282#ifdef BUILD_ECORE_CON
283
284# ifdef HAVE_CURL
285static int
286_ecore_file_download_url_compare_job(const void *data1, const void *data2)
287{
288 const Ecore_File_Download_Job *job = data1;
289 const Ecore_Con_Url *url = data2;
290
291 if (job->url_con == url) return 0;
292 return -1;
293}
294
295static Eina_Bool
296_ecore_file_download_url_complete_cb(void *data __UNUSED__, int type __UNUSED__, void *event)
297{
298 Ecore_Con_Event_Url_Complete *ev = event;
299 Ecore_File_Download_Job *job;
300
301 job = eina_list_search_unsorted(_job_list, _ecore_file_download_url_compare_job, ev->url_con);
302 if (!ECORE_MAGIC_CHECK(job, ECORE_MAGIC_FILE_DOWNLOAD_JOB)) return ECORE_CALLBACK_PASS_ON;
303
304 fclose(job->file);
305 if (job->completion_cb)
306 job->completion_cb(ecore_con_url_data_get(job->url_con), job->dst, ev->status);
307
308 _job_list = eina_list_remove(_job_list, job);
309 free(job->dst);
310 ecore_con_url_free(job->url_con);
311 free(job);
312
313 return ECORE_CALLBACK_DONE;
314}
315
316static Eina_Bool
317_ecore_file_download_url_progress_cb(void *data __UNUSED__, int type __UNUSED__, void *event)
318{
319/* this reports the downloads progress. if we return 0, then download
320 * continues, if we return anything else, then the download stops */
321 Ecore_Con_Event_Url_Progress *ev = event;
322 Ecore_File_Download_Job *job;
323
324 job = eina_list_search_unsorted(_job_list, _ecore_file_download_url_compare_job, ev->url_con);
325 if (!ECORE_MAGIC_CHECK(job, ECORE_MAGIC_FILE_DOWNLOAD_JOB)) return ECORE_CALLBACK_PASS_ON;
326
327 if (job->progress_cb)
328 if (job->progress_cb(ecore_con_url_data_get(job->url_con), job->dst,
329 (long int) ev->down.total, (long int) ev->down.now,
330 (long int) ev->up.total, (long int) ev->up.now) != 0)
331 {
332 _job_list = eina_list_remove(_job_list, job);
333 fclose(job->file);
334 free(job->dst);
335 free(job);
336
337 return ECORE_CALLBACK_PASS_ON;
338 }
339
340 return ECORE_CALLBACK_DONE;
341}
342
343Ecore_File_Download_Job *
344_ecore_file_download_curl(const char *url, const char *dst,
345 Ecore_File_Download_Completion_Cb completion_cb,
346 Ecore_File_Download_Progress_Cb progress_cb,
347 void *data,
348 Eina_Hash *headers)
349{
350 Ecore_File_Download_Job *job;
351
352 job = calloc(1, sizeof(Ecore_File_Download_Job));
353 if (!job) return NULL;
354
355 ECORE_MAGIC_SET(job, ECORE_MAGIC_FILE_DOWNLOAD_JOB);
356
357 job->file = fopen(dst, "wb");
358 if (!job->file)
359 {
360 free(job);
361 return NULL;
362 }
363 job->url_con = ecore_con_url_new(url);
364 if (!job->url_con)
365 {
366 fclose(job->file);
367 free(job);
368 return NULL;
369 }
370
371 if (headers) eina_hash_foreach(headers, _ecore_file_download_headers_foreach_cb, job);
372 ecore_con_url_fd_set(job->url_con, fileno(job->file));
373 ecore_con_url_data_set(job->url_con, data);
374
375 job->dst = strdup(dst);
376
377 job->completion_cb = completion_cb;
378 job->progress_cb = progress_cb;
379 _job_list = eina_list_append(_job_list, job);
380
381 if (!ecore_con_url_get(job->url_con))
382 {
383 ecore_con_url_free(job->url_con);
384 _job_list = eina_list_remove(_job_list, job);
385 fclose(job->file);
386 ecore_file_remove(job->dst);
387 free(job->dst);
388 free(job);
389 return NULL;
390 }
391
392 return job;
393}
394# endif
395#endif
396
397/**
398 * @brief Abort the given download job and call the completion_cb
399 * callbck with a status of 1 (error).
400 *
401 * @param job The download job to abort.
402 *
403 * This function aborts a download operation started by
404 * ecore_file_download(). @p job is the #Ecore_File_Download_Job
405 * structure filled by ecore_file_download(). If it is @c NULL, this
406 * function does nothing. To abort all the currently downloading
407 * operations, call ecore_file_download_abort_all().
408 */
409EAPI void
410ecore_file_download_abort(Ecore_File_Download_Job *job)
411{
412 if (!job)
413 return;
414
415#ifdef BUILD_ECORE_CON
416 if (job->completion_cb)
417 job->completion_cb(ecore_con_url_data_get(job->url_con), job->dst, 1);
418# ifdef HAVE_CURL
419 ecore_con_url_free(job->url_con);
420# endif
421 _job_list = eina_list_remove(_job_list, job);
422 fclose(job->file);
423 free(job->dst);
424 free(job);
425#endif /* BUILD_ECORE_CON */
426}
427
428/**
429 * @brief Abort all downloads.
430 *
431 * This function aborts all the downloads that have been started by
432 * ecore_file_download(). It loops over the started downloads and call
433 * ecore_file_download_abort() for each of them. To abort only one
434 * specific download operation, call ecore_file_download_abort().
435 */
436EAPI void
437ecore_file_download_abort_all(void)
438{
439#ifdef BUILD_ECORE_CON
440 Ecore_File_Download_Job *job;
441
442 EINA_LIST_FREE(_job_list, job)
443 ecore_file_download_abort(job);
444#endif /* BUILD_ECORE_CON */
445}
446
447/**
448 * @}
449 */