2005-06-15 18:54:12 -07:00
|
|
|
/*
|
|
|
|
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
|
|
|
|
*/
|
|
|
|
#include "ecore_file_private.h"
|
|
|
|
|
2005-09-07 01:50:25 -07:00
|
|
|
static int init = 0;
|
|
|
|
|
2005-06-17 16:52:32 -07:00
|
|
|
#ifdef HAVE_CURL
|
|
|
|
#include <curl/curl.h>
|
|
|
|
|
|
|
|
typedef struct _Ecore_File_Download_Job Ecore_File_Download_Job;
|
|
|
|
|
|
|
|
struct _Ecore_File_Download_Job
|
|
|
|
{
|
|
|
|
Ecore_Fd_Handler *fd_handler;
|
|
|
|
CURL *curl;
|
|
|
|
void (*completion_cb)(void *data, const char *file, int status);
|
2006-04-07 05:27:39 -07:00
|
|
|
int (*progress_cb)(void *data, const char *file, long int dltotal, long int dlnow, long int ultotal, long int ulnow);
|
2005-06-17 16:52:32 -07:00
|
|
|
void *data;
|
|
|
|
FILE *file;
|
|
|
|
char *dst;
|
|
|
|
};
|
|
|
|
|
|
|
|
Ecore_File_Download_Job *_ecore_file_download_curl(const char *url, const char *dst,
|
|
|
|
void (*completion_cb)(void *data, const char *file, int status),
|
2006-04-07 05:27:39 -07:00
|
|
|
int (*progress_cb)(void *data, const char *file, long int dltotal, long int dlnow, long int ultotal, long int ulnow),
|
2005-06-17 16:52:32 -07:00
|
|
|
void *data);
|
|
|
|
static int _ecore_file_download_curl_fd_handler(void *data, Ecore_Fd_Handler *fd_handler);
|
|
|
|
|
|
|
|
static CURLM *curlm;
|
|
|
|
static Ecore_List *_job_list;
|
|
|
|
static fd_set _current_fd_set;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int
|
|
|
|
ecore_file_download_init(void)
|
|
|
|
{
|
2005-09-07 01:57:08 -07:00
|
|
|
if (++init != 1) return init;
|
2005-09-07 01:50:25 -07:00
|
|
|
|
2005-06-17 16:52:32 -07:00
|
|
|
#ifdef HAVE_CURL
|
|
|
|
FD_ZERO(&_current_fd_set);
|
|
|
|
_job_list = ecore_list_new();
|
2005-09-07 01:50:25 -07:00
|
|
|
if (!_job_list) return --init;
|
2005-06-17 16:52:32 -07:00
|
|
|
|
|
|
|
if (curl_global_init(CURL_GLOBAL_NOTHING)) return 0;
|
|
|
|
|
|
|
|
curlm = curl_multi_init();
|
|
|
|
if (!curlm)
|
|
|
|
{
|
|
|
|
ecore_list_destroy(_job_list);
|
|
|
|
_job_list = NULL;
|
2005-09-07 01:50:25 -07:00
|
|
|
return --init;
|
2005-06-17 16:52:32 -07:00
|
|
|
}
|
|
|
|
#endif
|
2005-09-07 01:50:25 -07:00
|
|
|
return init;
|
2005-06-17 16:52:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
ecore_file_download_shutdown(void)
|
|
|
|
{
|
2005-09-07 01:57:08 -07:00
|
|
|
if (--init != 0) return init;
|
2005-06-17 16:52:32 -07:00
|
|
|
#ifdef HAVE_CURL
|
|
|
|
Ecore_File_Download_Job *job;
|
|
|
|
|
|
|
|
if (!ecore_list_is_empty(_job_list))
|
|
|
|
{
|
|
|
|
ecore_list_goto_first(_job_list);
|
|
|
|
while ((job = ecore_list_next(_job_list)))
|
|
|
|
{
|
|
|
|
ecore_main_fd_handler_del(job->fd_handler);
|
|
|
|
curl_multi_remove_handle(curlm, job->curl);
|
|
|
|
curl_easy_cleanup(job->curl);
|
|
|
|
fclose(job->file);
|
|
|
|
free(job->dst);
|
|
|
|
free(job);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ecore_list_destroy(_job_list);
|
|
|
|
curl_multi_cleanup(curlm);
|
|
|
|
curl_global_cleanup();
|
|
|
|
#endif
|
2005-09-07 01:50:25 -07:00
|
|
|
return init;
|
2005-06-17 16:52:32 -07:00
|
|
|
}
|
|
|
|
|
2006-09-08 09:52:29 -07:00
|
|
|
void
|
|
|
|
ecore_file_download_abort_all(void)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_CURL
|
|
|
|
Ecore_File_Download_Job *job;
|
|
|
|
|
|
|
|
if (!_job_list)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ecore_list_goto_first(_job_list);
|
|
|
|
while ((job = ecore_list_next(_job_list)))
|
|
|
|
{
|
|
|
|
ecore_main_fd_handler_del(job->fd_handler);
|
|
|
|
curl_multi_remove_handle(curlm, job->curl);
|
|
|
|
curl_easy_cleanup(job->curl);
|
|
|
|
fclose(job->file);
|
|
|
|
free(job->dst);
|
|
|
|
free(job);
|
|
|
|
}
|
|
|
|
ecore_list_clear(_job_list);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2006-01-06 10:46:30 -08:00
|
|
|
EAPI int
|
2005-06-17 16:52:32 -07:00
|
|
|
ecore_file_download(const char *url, const char *dst,
|
|
|
|
void (*completion_cb)(void *data, const char *file, int status),
|
2006-04-07 05:27:39 -07:00
|
|
|
int (*progress_cb)(void *data, const char *file, long int dltotal, long int dlnow, long int ultotal, long int ulnow),
|
2005-06-17 16:52:32 -07:00
|
|
|
void *data)
|
2005-06-15 18:54:12 -07:00
|
|
|
{
|
2006-01-06 10:46:30 -08:00
|
|
|
if (!ecore_file_is_dir(ecore_file_get_dir((char *)dst))) return 0;
|
2005-06-17 16:52:32 -07:00
|
|
|
if (ecore_file_exists(dst)) return 0;
|
2005-06-15 18:54:12 -07:00
|
|
|
|
|
|
|
/* FIXME: Add handlers for http and ftp! */
|
|
|
|
if (!strncmp(url, "file://", 7))
|
|
|
|
{
|
2005-06-17 16:52:32 -07:00
|
|
|
/* FIXME: Maybe fork? Might take a while to copy.
|
|
|
|
* Check filesize? */
|
2005-06-15 18:54:12 -07:00
|
|
|
/* Just copy it */
|
|
|
|
|
|
|
|
url += 7;
|
2005-06-17 16:52:32 -07:00
|
|
|
/* skip hostname */
|
|
|
|
url = strchr(url, '/');
|
|
|
|
return ecore_file_cp(url, dst);
|
|
|
|
}
|
|
|
|
#ifdef HAVE_CURL
|
|
|
|
else if ((!strncmp(url, "http://", 7)) ||
|
2005-06-22 07:51:37 -07:00
|
|
|
(!strncmp(url, "ftp://", 6)))
|
2005-06-17 16:52:32 -07:00
|
|
|
{
|
|
|
|
/* download */
|
|
|
|
Ecore_File_Download_Job *job;
|
|
|
|
|
2006-04-07 05:27:39 -07:00
|
|
|
job = _ecore_file_download_curl(url, dst, completion_cb, progress_cb, data);
|
2005-06-17 16:52:32 -07:00
|
|
|
if (job)
|
|
|
|
return 1;
|
|
|
|
else
|
|
|
|
return 0;
|
2005-06-15 18:54:12 -07:00
|
|
|
}
|
2005-06-17 16:52:32 -07:00
|
|
|
#endif
|
2005-06-15 18:54:12 -07:00
|
|
|
else
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2006-11-05 08:34:30 -08:00
|
|
|
#ifndef HAVE_CURL
|
|
|
|
completion_cb = NULL;
|
|
|
|
progress_cb = NULL;
|
|
|
|
data = NULL;
|
|
|
|
#endif
|
2005-06-15 18:54:12 -07:00
|
|
|
}
|
2005-06-17 16:52:32 -07:00
|
|
|
|
2006-01-06 10:46:30 -08:00
|
|
|
EAPI int
|
2005-06-22 07:51:37 -07:00
|
|
|
ecore_file_download_protocol_available(const char *protocol)
|
|
|
|
{
|
|
|
|
if (!strncmp(protocol, "file://", 7)) return 1;
|
|
|
|
#ifdef HAVE_CURL
|
|
|
|
else if (!strncmp(protocol, "http://", 7)) return 1;
|
|
|
|
else if (!strncmp(protocol, "ftp://", 6)) return 1;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-06-17 16:52:32 -07:00
|
|
|
#ifdef HAVE_CURL
|
2006-04-07 05:27:39 -07:00
|
|
|
/* this reports the downloads progress. if we return 0, then download
|
|
|
|
* continues, if we return anything else, then the download stops */
|
2006-11-10 11:11:12 -08:00
|
|
|
static int
|
|
|
|
_ecore_file_download_curl_progress_func(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
|
2006-04-07 05:27:39 -07:00
|
|
|
{
|
|
|
|
Ecore_File_Download_Job *job;
|
|
|
|
|
|
|
|
job = clientp;
|
|
|
|
|
|
|
|
if(job->progress_cb)
|
|
|
|
return job->progress_cb(job->data, job->dst, (long int)dltotal, (long int)dlnow, (long int)ultotal, (long int)ulnow);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-06-17 16:52:32 -07:00
|
|
|
Ecore_File_Download_Job *
|
|
|
|
_ecore_file_download_curl(const char *url, const char *dst,
|
|
|
|
void (*completion_cb)(void *data, const char *file,
|
|
|
|
int status),
|
2006-04-07 05:27:39 -07:00
|
|
|
int (*progress_cb)(void *data, const char *file,
|
|
|
|
long int dltotal, long int dlnow,
|
|
|
|
long int ultotal,
|
|
|
|
long int ulnow),
|
2005-06-17 16:52:32 -07:00
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
CURLMsg *curlmsg;
|
|
|
|
fd_set read_set, write_set, exc_set;
|
|
|
|
int fd_max;
|
|
|
|
int fd;
|
|
|
|
int flags;
|
|
|
|
int n_remaining, still_running;
|
|
|
|
Ecore_File_Download_Job *job;
|
|
|
|
|
|
|
|
job = calloc(1, sizeof(Ecore_File_Download_Job));
|
|
|
|
if (!job) return NULL;
|
|
|
|
|
|
|
|
job->file = fopen(dst, "wb");
|
|
|
|
if (!job->file)
|
|
|
|
{
|
|
|
|
free(job);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
job->curl = curl_easy_init();
|
|
|
|
if (!job->curl)
|
|
|
|
{
|
|
|
|
fclose(job->file);
|
|
|
|
free(job);
|
|
|
|
return NULL;
|
|
|
|
}
|
2006-04-07 05:27:39 -07:00
|
|
|
|
2005-06-17 16:52:32 -07:00
|
|
|
curl_easy_setopt(job->curl, CURLOPT_URL, url);
|
|
|
|
curl_easy_setopt(job->curl, CURLOPT_WRITEDATA, job->file);
|
2006-04-07 05:27:39 -07:00
|
|
|
|
|
|
|
if(progress_cb)
|
|
|
|
{
|
|
|
|
curl_easy_setopt(job->curl, CURLOPT_NOPROGRESS, FALSE);
|
|
|
|
curl_easy_setopt(job->curl, CURLOPT_PROGRESSDATA, job);
|
|
|
|
curl_easy_setopt(job->curl, CURLOPT_PROGRESSFUNCTION, _ecore_file_download_curl_progress_func);
|
|
|
|
}
|
|
|
|
|
2005-06-17 16:52:32 -07:00
|
|
|
job->data = data;
|
|
|
|
job->completion_cb = completion_cb;
|
2006-04-07 05:27:39 -07:00
|
|
|
job->progress_cb = progress_cb;
|
2005-06-17 16:52:32 -07:00
|
|
|
job->dst = strdup(dst);
|
|
|
|
ecore_list_append(_job_list, job);
|
|
|
|
|
|
|
|
curl_multi_add_handle(curlm, job->curl);
|
|
|
|
while (curl_multi_perform(curlm, &still_running) == CURLM_CALL_MULTI_PERFORM);
|
|
|
|
|
|
|
|
/* check for completed jobs */
|
|
|
|
while ((curlmsg = curl_multi_info_read(curlm, &n_remaining)) != NULL)
|
|
|
|
{
|
|
|
|
Ecore_File_Download_Job *current;
|
|
|
|
|
|
|
|
if (curlmsg->msg != CURLMSG_DONE) continue;
|
|
|
|
|
|
|
|
/* find the job which is done */
|
|
|
|
ecore_list_goto_first(_job_list);
|
|
|
|
while ((current = ecore_list_current(_job_list)))
|
|
|
|
{
|
|
|
|
if (curlmsg->easy_handle == current->curl)
|
|
|
|
{
|
|
|
|
/* We have a match -- delete the job */
|
|
|
|
if (current == job)
|
|
|
|
job = NULL;
|
|
|
|
if (current->fd_handler)
|
|
|
|
{
|
|
|
|
FD_CLR(ecore_main_fd_handler_fd_get(current->fd_handler),
|
|
|
|
&_current_fd_set);
|
|
|
|
ecore_main_fd_handler_del(current->fd_handler);
|
|
|
|
}
|
|
|
|
ecore_list_remove(_job_list);
|
|
|
|
curl_multi_remove_handle(curlm, current->curl);
|
|
|
|
curl_easy_cleanup(current->curl);
|
|
|
|
fclose(current->file);
|
2005-06-21 19:00:35 -07:00
|
|
|
if (current->completion_cb)
|
|
|
|
current->completion_cb(current->data, current->dst,
|
|
|
|
curlmsg->data.result);
|
2005-06-17 16:52:32 -07:00
|
|
|
free(current->dst);
|
|
|
|
free(current);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ecore_list_next(_job_list);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (job)
|
|
|
|
{
|
|
|
|
FD_ZERO(&read_set);
|
|
|
|
FD_ZERO(&write_set);
|
|
|
|
FD_ZERO(&exc_set);
|
|
|
|
|
|
|
|
/* Stupid curl, why can't I get the fd to the current added job? */
|
|
|
|
curl_multi_fdset(curlm, &read_set, &write_set, &exc_set, &fd_max);
|
|
|
|
for (fd = 0; fd <= fd_max; fd++)
|
|
|
|
{
|
|
|
|
if (!FD_ISSET(fd, &_current_fd_set))
|
|
|
|
{
|
|
|
|
flags = 0;
|
|
|
|
if (FD_ISSET(fd, &read_set)) flags |= ECORE_FD_READ;
|
|
|
|
if (FD_ISSET(fd, &write_set)) flags |= ECORE_FD_WRITE;
|
|
|
|
if (FD_ISSET(fd, &exc_set)) flags |= ECORE_FD_ERROR;
|
|
|
|
if (flags)
|
|
|
|
{
|
|
|
|
FD_SET(fd, &_current_fd_set);
|
|
|
|
job->fd_handler = ecore_main_fd_handler_add(fd, flags,
|
|
|
|
_ecore_file_download_curl_fd_handler,
|
|
|
|
NULL, NULL, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!job->fd_handler)
|
|
|
|
{
|
|
|
|
curl_easy_cleanup(job->curl);
|
|
|
|
fclose(job->file);
|
|
|
|
free(job);
|
|
|
|
job = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return job;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2006-11-10 11:11:12 -08:00
|
|
|
_ecore_file_download_curl_fd_handler(void *data __UNUSED__, Ecore_Fd_Handler *fd_handler __UNUSED__)
|
2005-06-17 16:52:32 -07:00
|
|
|
{
|
|
|
|
Ecore_File_Download_Job *job;
|
|
|
|
CURLMsg *curlmsg;
|
|
|
|
int n_remaining, still_running;
|
|
|
|
|
|
|
|
/* FIXME: Can this run for a long time? Maybe limit how long it can run */
|
|
|
|
while (curl_multi_perform(curlm, &still_running) == CURLM_CALL_MULTI_PERFORM);
|
|
|
|
|
|
|
|
/* Loop jobs and check if any are done */
|
|
|
|
while ((curlmsg = curl_multi_info_read(curlm, &n_remaining)) != NULL)
|
|
|
|
{
|
|
|
|
if (curlmsg->msg != CURLMSG_DONE) continue;
|
|
|
|
|
|
|
|
/* find the job which is done */
|
|
|
|
ecore_list_goto_first(_job_list);
|
|
|
|
while ((job = ecore_list_current(_job_list)))
|
|
|
|
{
|
|
|
|
if (curlmsg->easy_handle == job->curl)
|
|
|
|
{
|
|
|
|
/* We have a match -- delete the job */
|
|
|
|
FD_CLR(ecore_main_fd_handler_fd_get(job->fd_handler),
|
|
|
|
&_current_fd_set);
|
|
|
|
ecore_list_remove(_job_list);
|
|
|
|
ecore_main_fd_handler_del(job->fd_handler);
|
|
|
|
curl_multi_remove_handle(curlm, job->curl);
|
|
|
|
curl_easy_cleanup(job->curl);
|
|
|
|
fclose(job->file);
|
2005-06-21 19:00:35 -07:00
|
|
|
if (job->completion_cb)
|
|
|
|
job->completion_cb(job->data, job->dst, !curlmsg->data.result);
|
2005-06-17 16:52:32 -07:00
|
|
|
free(job->dst);
|
|
|
|
free(job);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ecore_list_next(_job_list);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
#endif
|