9 # include "Ecore_Con.h"
12 #include "ecore_file_private.h"
14 #ifdef BUILD_ECORE_CON
16 #define ECORE_MAGIC_FILE_DOWNLOAD_JOB 0xf7427cb8
18 struct _Ecore_File_Download_Job
22 Ecore_Con_Url *url_con;
27 Ecore_File_Download_Completion_Cb completion_cb;
28 Ecore_File_Download_Progress_Cb progress_cb;
32 Ecore_File_Download_Job *_ecore_file_download_curl(const char *url, const char *dst,
33 Ecore_File_Download_Completion_Cb completion_cb,
34 Ecore_File_Download_Progress_Cb progress_cb,
38 static Eina_Bool _ecore_file_download_url_complete_cb(void *data, int type, void *event);
39 static Eina_Bool _ecore_file_download_url_progress_cb(void *data, int type, void *event);
42 static Ecore_Event_Handler *_url_complete_handler = NULL;
43 static Ecore_Event_Handler *_url_progress_download = NULL;
44 static Eina_List *_job_list;
46 #endif /* BUILD_ECORE_CON */
49 ecore_file_download_init(void)
51 #ifdef BUILD_ECORE_CON
52 if (!ecore_con_url_init())
56 _url_complete_handler = ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE, _ecore_file_download_url_complete_cb, NULL);
57 _url_progress_download = ecore_event_handler_add(ECORE_CON_EVENT_URL_PROGRESS, _ecore_file_download_url_progress_cb, NULL);
60 #endif /* BUILD_ECORE_CON */
66 ecore_file_download_shutdown(void)
68 #ifdef BUILD_ECORE_CON
69 if (_url_complete_handler)
70 ecore_event_handler_del(_url_complete_handler);
71 if (_url_progress_download)
72 ecore_event_handler_del(_url_progress_download);
73 _url_complete_handler = NULL;
74 _url_progress_download = NULL;
75 ecore_file_download_abort_all();
77 ecore_con_url_shutdown();
78 #endif /* BUILD_ECORE_CON */
81 #ifdef BUILD_ECORE_CON
84 _ecore_file_download_headers_foreach_cb(const Eina_Hash *hash __UNUSED__, const void *key, void *data, void *fdata)
86 Ecore_File_Download_Job *job = fdata;
87 ecore_con_url_additional_header_add(job->url_con, key, data);
95 _ecore_file_download(const char *url,
97 Ecore_File_Download_Completion_Cb completion_cb,
98 Ecore_File_Download_Progress_Cb progress_cb,
100 Ecore_File_Download_Job **job_ret,
103 #ifdef BUILD_ECORE_CON
104 char *dir = ecore_file_dir_get(dst);
106 if (!ecore_file_is_dir(dir))
108 EINA_LOG_ERR("%s is not a directory", dir);
113 if (ecore_file_exists(dst))
115 EINA_LOG_ERR("%s already exists", dst);
119 if (!strncmp(url, "file://", 7))
121 /* FIXME: Maybe fork? Might take a while to copy.
127 url = strchr(url, '/');
128 return ecore_file_cp(url, dst);
131 else if ((!strncmp(url, "http://", 7)) || (!strncmp(url, "https://", 8)) ||
132 (!strncmp(url, "ftp://", 6)))
135 Ecore_File_Download_Job *job;
137 job = _ecore_file_download_curl(url, dst, completion_cb, progress_cb, data, headers);
138 if(job_ret) *job_ret = job;
143 EINA_LOG_ERR("no job returned\n");
146 return job ? EINA_TRUE : EINA_FALSE;
149 else if ((!strncmp(url, "http://", 7)) || (!strncmp(url, "https://", 8)) ||
150 (!strncmp(url, "ftp://", 6)))
164 completion_cb = NULL;
168 #endif /* BUILD_ECORE_CON */
172 * @addtogroup Ecore_File_Group Ecore_File - Files and directories convenience functions
178 * @brief Download the given url to the given destination.
180 * @param url The complete url to download.
181 * @param dst The local file to save the downloaded to.
182 * @param completion_cb A callback called on download complete.
183 * @param progress_cb A callback called during the download operation.
184 * @param data User data passed to both callbacks.
185 * @param job_ret Job used to abort the download.
186 * @return EINA_TRUE if the download start or EINA_FALSE on failure
188 * This function starts the download of the URL @p url and saves it to
189 * @p dst. @p url must provide the protocol, including 'http://',
190 * 'ftp://' or 'file://'. Ecore_File must be compiled with CURL to
191 * download using http and ftp protocols. If @p dst is ill-formed, or
192 * if it already exists, the function returns EINA_FALSE. When the
193 * download is complete, the callback @p completion_cb is called and
194 * @p data is passed to it. The @p status parameter of @p completion_cb
195 * will be filled with the status of the download (200, 404,...). The
196 * @p progress_cb is called during the download operation, each time a
197 * packet is received or when CURL wants. It can be used to display the
198 * percentage of the downloaded file. Return 0 from this callback, if provided,
199 * to continue the operation or anything else to abort the download. The only
200 * operations that can be aborted are those with protocol 'http' or 'ftp'. In
201 * that case @p job_ret can be filled. It can be used with
202 * ecore_file_download_abort() or ecore_file_download_abort_all() to
203 * respectively abort one or all download operations. This function returns
204 * EINA_TRUE if the download starts, EINA_FALSE otherwise.
207 ecore_file_download(const char *url,
209 Ecore_File_Download_Completion_Cb completion_cb,
210 Ecore_File_Download_Progress_Cb progress_cb,
212 Ecore_File_Download_Job **job_ret)
214 return _ecore_file_download(url, dst, completion_cb, progress_cb, data, job_ret, NULL);
218 * @brief Download the given url to the given destination with additional headers.
220 * @param url The complete url to download.
221 * @param dst The local file to save the downloaded to.
222 * @param completion_cb A callback called on download complete.
223 * @param progress_cb A callback called during the download operation.
224 * @param data User data passed to both callbacks.
225 * @param job_ret Job used to abort the download.
226 * @param headers pointer of header lists.
227 * @return EINA_TRUE if the download start or EINA_FALSE on failure
230 ecore_file_download_full(const char *url,
232 Ecore_File_Download_Completion_Cb completion_cb,
233 Ecore_File_Download_Progress_Cb progress_cb,
235 Ecore_File_Download_Job **job_ret,
238 return _ecore_file_download(url, dst, completion_cb, progress_cb, data, job_ret, headers);
242 * @brief Check if the given protocol is available.
244 * @param protocol The protocol to check.
245 * @return EINA_TRUE if protocol is handled, EINA_FALSE otherwise.
247 * This function returns EINA_TRUE if @p protocol is supported,
248 * EINA_FALSE otherwise. @p protocol can be 'http://', 'ftp://' or
249 * 'file://'. Ecore_FILE must be compiled with CURL to handle http and
253 ecore_file_download_protocol_available(const char *protocol)
255 #ifdef BUILD_ECORE_CON
256 if (!strncmp(protocol, "file://", 7)) return EINA_TRUE;
258 else if (!strncmp(protocol, "http://", 7)) return EINA_TRUE;
259 else if (!strncmp(protocol, "ftp://", 6)) return EINA_TRUE;
261 #endif /* BUILD_ECORE_CON */
266 #ifdef BUILD_ECORE_CON
270 _ecore_file_download_url_compare_job(const void *data1, const void *data2)
272 const Ecore_File_Download_Job *job = data1;
273 const Ecore_Con_Url *url = data2;
275 if (job->url_con == url) return 0;
280 _ecore_file_download_url_complete_cb(void *data __UNUSED__, int type __UNUSED__, void *event)
282 Ecore_Con_Event_Url_Complete *ev = event;
283 Ecore_File_Download_Job *job;
285 job = eina_list_search_unsorted(_job_list, _ecore_file_download_url_compare_job, ev->url_con);
286 if (!ECORE_MAGIC_CHECK(job, ECORE_MAGIC_FILE_DOWNLOAD_JOB)) return ECORE_CALLBACK_PASS_ON;
288 if (job->completion_cb)
289 job->completion_cb(ecore_con_url_data_get(job->url_con), job->dst, !ev->status);
291 _job_list = eina_list_remove(_job_list, job);
294 ecore_con_url_free(job->url_con);
297 return ECORE_CALLBACK_DONE;
301 _ecore_file_download_url_progress_cb(void *data __UNUSED__, int type __UNUSED__, void *event)
303 /* this reports the downloads progress. if we return 0, then download
304 * continues, if we return anything else, then the download stops */
305 Ecore_Con_Event_Url_Progress *ev = event;
306 Ecore_File_Download_Job *job;
308 job = eina_list_search_unsorted(_job_list, _ecore_file_download_url_compare_job, ev->url_con);
309 if (!ECORE_MAGIC_CHECK(job, ECORE_MAGIC_FILE_DOWNLOAD_JOB)) return ECORE_CALLBACK_PASS_ON;
311 if (job->progress_cb)
312 if (job->progress_cb(ecore_con_url_data_get(job->url_con), job->dst,
313 (long int) ev->down.total, (long int) ev->down.now,
314 (long int) ev->up.total, (long int) ev->up.now) != 0)
316 _job_list = eina_list_remove(_job_list, job);
321 return ECORE_CALLBACK_PASS_ON;
324 return ECORE_CALLBACK_DONE;
327 Ecore_File_Download_Job *
328 _ecore_file_download_curl(const char *url, const char *dst,
329 Ecore_File_Download_Completion_Cb completion_cb,
330 Ecore_File_Download_Progress_Cb progress_cb,
334 Ecore_File_Download_Job *job;
336 job = calloc(1, sizeof(Ecore_File_Download_Job));
337 if (!job) return NULL;
339 ECORE_MAGIC_SET(job, ECORE_MAGIC_FILE_DOWNLOAD_JOB);
341 job->file = fopen(dst, "wb");
347 job->url_con = ecore_con_url_new(url);
355 if (headers) eina_hash_foreach(headers, _ecore_file_download_headers_foreach_cb, job);
356 ecore_con_url_fd_set(job->url_con, fileno(job->file));
357 ecore_con_url_data_set(job->url_con, data);
359 job->dst = strdup(dst);
361 job->completion_cb = completion_cb;
362 job->progress_cb = progress_cb;
363 _job_list = eina_list_append(_job_list, job);
365 ecore_con_url_get(job->url_con);
373 * @brief Abort the given download job and call the completion_cb
374 * callbck with a status of 1 (error).
376 * @param job The download job to abort.
378 * This function aborts a download operation started by
379 * ecore_file_download(). @p job is the #Ecore_File_Download_Job
380 * structure filled by ecore_file_download(). If it is @c NULL, this
381 * function does nothing. To abort all the currently downloading
382 * operations, call ecore_file_download_abort_all().
385 ecore_file_download_abort(Ecore_File_Download_Job *job)
390 #ifdef BUILD_ECORE_CON
391 if (job->completion_cb)
392 job->completion_cb(ecore_con_url_data_get(job->url_con), job->dst, 1);
394 ecore_con_url_free(job->url_con);
396 _job_list = eina_list_remove(_job_list, job);
400 #endif /* BUILD_ECORE_CON */
404 * @brief Abort all downloads.
406 * This function aborts all the downloads that have been started by
407 * ecore_file_download(). It loops over the started downloads and call
408 * ecore_file_download_abort() for each of them. To abort only one
409 * specific download operation, call ecore_file_download_abort().
412 ecore_file_download_abort_all(void)
414 #ifdef BUILD_ECORE_CON
415 Ecore_File_Download_Job *job;
417 EINA_LIST_FREE(_job_list, job)
418 ecore_file_download_abort(job);
419 #endif /* BUILD_ECORE_CON */