From 4548e51fa5d73686d77ba4032e07bd08188e4387 Mon Sep 17 00:00:00 2001 From: sebastid Date: Fri, 17 Jun 2005 23:52:32 +0000 Subject: [PATCH] Download files with CURL. Thanks to Simon Poole. SVN revision: 15400 --- legacy/ecore/configure.in | 24 +- legacy/ecore/src/lib/ecore_file/Ecore_File.h | 6 +- legacy/ecore/src/lib/ecore_file/Makefile.am | 5 +- legacy/ecore/src/lib/ecore_file/ecore_file.c | 4 + .../src/lib/ecore_file/ecore_file_download.c | 271 +++++++++++++++++- .../src/lib/ecore_file/ecore_file_private.h | 13 +- 6 files changed, 309 insertions(+), 14 deletions(-) diff --git a/legacy/ecore/configure.in b/legacy/ecore/configure.in index 23674fd6da..24a64a3b12 100644 --- a/legacy/ecore/configure.in +++ b/legacy/ecore/configure.in @@ -793,6 +793,7 @@ ecore_file_libs="" use_fam="no" use_inotify="no" use_poll="no" +use_curl="no" AC_MSG_CHECKING(whether ecore_file module is to be built) AC_ARG_ENABLE(ecore-file, @@ -882,6 +883,23 @@ if test "x$use_poll" = "xyes"; then AC_DEFINE(HAVE_POLL, 1, [ File monitoring with polling ]) fi +curl_flags="" +curl_libs="" +# Check for CURL +AC_ARG_WITH(curl-config, [ --with-curl-config=CURL_CONFIG use curl-config specified ], + [ CURL_CONFIG=$withval; + echo "using "$CURL_CONFIG" for curl-config"; ], + [ if test -z "$CURL_CONFIG"; then + AC_PATH_PROG(CURL_CONFIG, "curl-config", "", $PATH) + fi + ]) +if test "$CURL_CONFIG"; then + use_curl="yes" + curl_cflags=`$CURL_CONFIG --cflags` + curl_libs=`$CURL_CONFIG --libs` + AC_DEFINE(HAVE_CURL, 1, [Downloading with CURL]) +fi + if test "x$have_ecore_file" = "xyes"; then AM_CONDITIONAL(BUILD_ECORE_FILE, true) ecore_file_libs="-lecore_file" @@ -889,7 +907,9 @@ if test "x$have_ecore_file" = "xyes"; then else AM_CONDITIONAL(BUILD_ECORE_FILE, false) fi -ecore_file_libs="$ecore_file_libs $fam_libs" +ecore_file_libs="$ecore_file_libs $fam_libs $curl_libs" +AC_SUBST(curl_cflags) +AC_SUBST(curl_libs) AC_SUBST(fam_libs) AC_SUBST(ecore_file_libs) @@ -1000,7 +1020,7 @@ echo " Ecore_Ipc...............: $have_ecore_ipc (OpenSSL: $use_openssl)" echo " Ecore_Config............: $have_ecore_config" echo " Ecore_DBUS..............: $have_ecore_dbus" #echo " Ecore_File..............: $have_ecore_file (Inotify: $use_inotify) (FAM: $use_fam) (Poll: $use_poll)" -echo " Ecore_File..............: $have_ecore_file (Inotify: $use_inotify) (Poll: $use_poll)" +echo " Ecore_File..............: $have_ecore_file (Inotify: $use_inotify) (Poll: $use_poll) (CURL: $use_curl)" echo echo "Now type 'make' ('gmake' on some systems) to compile $PACKAGE." echo diff --git a/legacy/ecore/src/lib/ecore_file/Ecore_File.h b/legacy/ecore/src/lib/ecore_file/Ecore_File.h index cf235fa60b..925b3b6257 100644 --- a/legacy/ecore/src/lib/ecore_file/Ecore_File.h +++ b/legacy/ecore/src/lib/ecore_file/Ecore_File.h @@ -78,7 +78,11 @@ extern "C" { EAPI int ecore_file_app_installed(const char *app); - EAPI int ecore_file_download(const char *url, const char *dst_dir); + EAPI int ecore_file_download(const char *url, const char *dst, + void (*completion_cb)(void *data, + const char *file, + int status), + void *data); #ifdef __cplusplus } diff --git a/legacy/ecore/src/lib/ecore_file/Makefile.am b/legacy/ecore/src/lib/ecore_file/Makefile.am index fbdaf260b1..6aceac6df8 100644 --- a/legacy/ecore/src/lib/ecore_file/Makefile.am +++ b/legacy/ecore/src/lib/ecore_file/Makefile.am @@ -2,7 +2,8 @@ MAINTAINERCLEANFILES = Makefile.in INCLUDES = \ -I$(top_srcdir)/src/lib/ecore \ --I$(top_builddir)/src/lib/ecore +-I$(top_builddir)/src/lib/ecore \ +@curl_cflags@ libecore_file_la_LDFLAGS = -version-info 1:0:0 \ -L$(top_builddir)/src/lib/ecore/.libs @@ -24,7 +25,7 @@ ecore_file_download.c libecore_file_la_LIBADD = \ $(top_builddir)/src/lib/ecore/libecore.la \ -@fam_libs@ +@fam_libs@ @curl_libs@ endif diff --git a/legacy/ecore/src/lib/ecore_file/ecore_file.c b/legacy/ecore/src/lib/ecore_file/ecore_file.c index 37dbdc1350..e71fc1912b 100644 --- a/legacy/ecore/src/lib/ecore_file/ecore_file.c +++ b/legacy/ecore/src/lib/ecore_file/ecore_file.c @@ -11,6 +11,8 @@ ecore_file_init() return 0; if (!ecore_file_path_init()) return 0; + if (!ecore_file_download_init()) + return 0; return 1; } @@ -21,6 +23,8 @@ ecore_file_shutdown() return 0; if (!ecore_file_path_shutdown()) return 0; + if (!ecore_file_download_shutdown()) + return 0; return 1; } diff --git a/legacy/ecore/src/lib/ecore_file/ecore_file_download.c b/legacy/ecore/src/lib/ecore_file/ecore_file_download.c index d882f4b95c..cb6d372ee7 100644 --- a/legacy/ecore/src/lib/ecore_file/ecore_file_download.c +++ b/legacy/ecore/src/lib/ecore_file/ecore_file_download.c @@ -3,23 +3,282 @@ */ #include "ecore_file_private.h" -int -ecore_file_download(const char *url, const char *dst_dir) +#ifdef HAVE_CURL +#include + +typedef struct _Ecore_File_Download_Job Ecore_File_Download_Job; + +struct _Ecore_File_Download_Job { - if (!ecore_file_is_dir(dst_dir)) return 0; + Ecore_Fd_Handler *fd_handler; + CURL *curl; + void (*completion_cb)(void *data, const char *file, int status); + 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), + 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) +{ +#ifdef HAVE_CURL + FD_ZERO(&_current_fd_set); + _job_list = ecore_list_new(); + if (!_job_list) return 0; + + if (curl_global_init(CURL_GLOBAL_NOTHING)) return 0; + + curlm = curl_multi_init(); + if (!curlm) + { + ecore_list_destroy(_job_list); + _job_list = NULL; + return 0; + } +#endif + return 1; +} + +int +ecore_file_download_shutdown(void) +{ +#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 + return 1; +} + +int +ecore_file_download(const char *url, const char *dst, + void (*completion_cb)(void *data, const char *file, int status), + void *data) +{ + if (!ecore_file_is_dir(ecore_file_get_dir(dst))) return 0; + if (ecore_file_exists(dst)) return 0; /* FIXME: Add handlers for http and ftp! */ if (!strncmp(url, "file://", 7)) { + /* FIXME: Maybe fork? Might take a while to copy. + * Check filesize? */ /* Just copy it */ - char buf[PATH_MAX]; url += 7; - snprintf(buf, sizeof(buf), "%s/%s", dst_dir, ecore_file_get_file(url)); - return ecore_file_cp(url, buf); + /* skip hostname */ + url = strchr(url, '/'); + return ecore_file_cp(url, dst); } +#ifdef HAVE_CURL + else if ((!strncmp(url, "http://", 7)) || + (!strncmp(url, "ftp://", 7))) + { + /* download */ + Ecore_File_Download_Job *job; + + job = _ecore_file_download_curl(url, dst, completion_cb, data); + if (job) + return 1; + else + return 0; + } +#endif else { return 0; } } + +#ifdef HAVE_CURL +/* + * FIXME: Use + * CURLOPT_PROGRESSFUNCTION and CURLOPT_PROGRESSDATA to + * get reports on progress. + * And maybe other nifty functions... + */ +Ecore_File_Download_Job * +_ecore_file_download_curl(const char *url, const char *dst, + void (*completion_cb)(void *data, const char *file, + int status), + 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; + } + curl_easy_setopt(job->curl, CURLOPT_URL, url); + curl_easy_setopt(job->curl, CURLOPT_WRITEDATA, job->file); + + job->data = data; + job->completion_cb = completion_cb; + 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); + } + if (current->completion_cb) + current->completion_cb(current->data, current->dst, + curlmsg->data.result); + ecore_list_remove(_job_list); + curl_multi_remove_handle(curlm, current->curl); + curl_easy_cleanup(current->curl); + fclose(current->file); + 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); + printf("max: %d\n", fd_max); + for (fd = 0; fd <= fd_max; fd++) + { + if (!FD_ISSET(fd, &_current_fd_set)) + { + printf("Found %d!!!\n", fd); + 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; + printf("flags: %d\n", flags); + 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) + { + printf("No fd handler?\n"); + curl_easy_cleanup(job->curl); + fclose(job->file); + free(job); + job = NULL; + } + } + + return job; +} + +static int +_ecore_file_download_curl_fd_handler(void *data, Ecore_Fd_Handler *fd_handler) +{ + 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); + if (job->completion_cb) + job->completion_cb(job->data, job->dst, !curlmsg->data.result); + 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); + free(job->dst); + free(job); + break; + } + ecore_list_next(_job_list); + } + } + return 1; +} +#endif diff --git a/legacy/ecore/src/lib/ecore_file/ecore_file_private.h b/legacy/ecore/src/lib/ecore_file/ecore_file_private.h index b8b9e7c4ed..b691655875 100644 --- a/legacy/ecore/src/lib/ecore_file/ecore_file_private.h +++ b/legacy/ecore/src/lib/ecore_file/ecore_file_private.h @@ -10,12 +10,10 @@ #include "Ecore.h" #include "Ecore_File.h" +/* ecore_file_monitor */ int ecore_file_monitor_init(void); int ecore_file_monitor_shutdown(void); -int ecore_file_path_init(void); -int ecore_file_path_shutdown(void); - #define ECORE_FILE_MONITOR(x) ((Ecore_File_Monitor *)(x)) struct _Ecore_File_Monitor @@ -65,4 +63,13 @@ EAPI Ecore_File_Monitor *ecore_file_monitor_poll_add(const char *path, const char *path), void *data); EAPI void ecore_file_monitor_poll_del(Ecore_File_Monitor *ecore_file_monitor); + +/* ecore_file_path */ +int ecore_file_path_init(void); +int ecore_file_path_shutdown(void); + +/* ecore_file_download */ +int ecore_file_download_init(void); +int ecore_file_download_shutdown(void); + #endif