summaryrefslogtreecommitdiff
path: root/legacy/ecore/src/lib/ecore_file/ecore_file_download.c
blob: c855c7135e252bf8d2adf804d269f547cf7d046f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
/*
 * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
 */

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <stdio.h>
#include <string.h>

#include "Ecore_Con.h"
#include "ecore_file_private.h"

#define ECORE_MAGIC_FILE_DOWNLOAD_JOB	0xf7427cb8

typedef struct _Ecore_File_Download_Job		Ecore_File_Download_Job;
struct _Ecore_File_Download_Job
{
   ECORE_MAGIC;

   Ecore_Con_Url	*url_con;
   FILE			*file;

   char			*dst;

   void	(*completion_cb)(void *data, const char *file, int status);

   int	(*progress_cb)  (void *data, const char *file,
			 long int dltotal, long int dlnow,
			 long int ultotal, long int ulnow);
};

#ifdef HAVE_CURL
Ecore_File_Download_Job *_ecore_file_download_curl(const char *url, const char *dst,
						   void (*completion_cb)(void *data, const char *file, int status),
						   int (*progress_cb)(void *data, const char *file, long int dltotal, long int dlnow, long int ultotal, long int ulnow),
						   void *data);

static int _ecore_file_download_url_complete_cb(void *data, int type, void *event);
static int _ecore_file_download_url_progress_cb(void *data, int type, void *event);
#endif
static void _ecore_file_download_abort(Ecore_File_Download_Job *job);

static int			 init = 0;
static Ecore_Event_Handler	*_url_complete_handler = NULL;
static Ecore_Event_Handler	*_url_progress_download = NULL;
static Eina_List		*_job_list;

EAPI int
ecore_file_download_init(void)
{
#ifndef _WIN32
   ecore_con_url_init();

   if (init++ == 0)
     {
#ifdef HAVE_CURL
	_url_complete_handler = ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE, _ecore_file_download_url_complete_cb, NULL);
	_url_progress_download = ecore_event_handler_add(ECORE_CON_EVENT_URL_PROGRESS, _ecore_file_download_url_progress_cb, NULL);
#endif
     }

   return 1;
#else
   return 0;
#endif
}

EAPI int
ecore_file_download_shutdown(void)
{
#ifndef _WIN32
   if (--init == 0)
     {
	if (_url_complete_handler)
	  ecore_event_handler_del(_url_complete_handler);
	if (_url_progress_download)
	  ecore_event_handler_del(_url_progress_download);
	_url_complete_handler = NULL;
	_url_progress_download = NULL;
	ecore_file_download_abort_all();
     }

   return ecore_con_url_shutdown();
#else
   return 0;
#endif
}

EAPI void
ecore_file_download_abort_all(void)
{
	Ecore_File_Download_Job *job;

   EINA_LIST_FREE(_job_list, job)
	     _ecore_file_download_abort(job);
}

/**
 * Download @p url to the given @p dst
 * @param  url The complete url to download
 * @param  dst The local file to save the downloaded to
 * @param  completion_cb A callback called on download complete
 * @param  progress_cb A callback called during the download operation
 * @return 1 if the download start or 0 on failure
 *
 * You must provide the full url, including 'http://', 'ftp://' or 'file://'.\n
 * If @p dst already exist it will not be overwritten and the function will fail.\n
 * Ecore must be compiled with CURL to download using http and ftp protocols.
 */
EAPI int
ecore_file_download(const char *url, const char *dst,
		    void (*completion_cb)(void *data, const char *file, int status),
		    int (*progress_cb)(void *data, const char *file, long int dltotal, long int dlnow, long int ultotal, long int ulnow),
		    void *data)
{
   char *dir = ecore_file_dir_get(dst);

   if (!ecore_file_is_dir(dir))
     {
	free(dir);
	return 0;
     }
   free(dir);
   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 */

	url += 7;
	/* skip hostname */
	url = strchr(url, '/');
	return ecore_file_cp(url, dst);
     }
#ifdef HAVE_CURL
   else if ((!strncmp(url, "http://", 7)) ||
	    (!strncmp(url, "ftp://", 6)))
     {
	/* download */
	Ecore_File_Download_Job *job;

	job = _ecore_file_download_curl(url, dst, completion_cb, progress_cb, data);
	if (job)
	  return 1;
	else
	  return 0;
     }
#endif
   else
     {
	return 0;
     }
#ifndef HAVE_CURL
   completion_cb = NULL;
   progress_cb = NULL;
   data = NULL;
#endif
}

/**
 * Check if the given protocol is available
 * @param  protocol The protocol to check
 * @return 1 if protocol is handled or 0 if not
 *
 * @p protocol can be 'http://', 'ftp://' or 'file://'.\n
 * Ecore must be compiled with CURL to handle http and ftp protocols.
 */
EAPI int
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;
}

#ifdef HAVE_CURL
static int
_ecore_file_download_url_compare_job(const void *data1, const void *data2)
{
   const Ecore_File_Download_Job	*job = data1;
   const Ecore_Con_Url			*url = data2;

   if (job->url_con == url) return 0;
   return -1;
}

static int
_ecore_file_download_url_complete_cb(void *data, int type, void *event)
{
   Ecore_Con_Event_Url_Complete	*ev = event;
   Ecore_File_Download_Job	*job;

   job = eina_list_search_unsorted(_job_list, _ecore_file_download_url_compare_job, ev->url_con);
   if (!ECORE_MAGIC_CHECK(job, ECORE_MAGIC_FILE_DOWNLOAD_JOB)) return 1;

   _job_list = eina_list_remove(_job_list, job);

   if (job->completion_cb)
     job->completion_cb(ecore_con_url_data_get(job->url_con), job->dst, !ev->status);

   _ecore_file_download_abort(job);

   return 0;
}

static int
_ecore_file_download_url_progress_cb(void *data, int type, void *event)
{
/* this reports the downloads progress. if we return 0, then download
 * continues, if we return anything else, then the download stops */
   Ecore_Con_Event_Url_Progress	*ev = event;
   Ecore_File_Download_Job	*job;

   job = eina_list_search_unsorted(_job_list, _ecore_file_download_url_compare_job, ev->url_con);
   if (!ECORE_MAGIC_CHECK(job, ECORE_MAGIC_FILE_DOWNLOAD_JOB)) return 1;

   if (job->progress_cb)
     if (job->progress_cb(ecore_con_url_data_get(job->url_con), job->dst,
			  (long int) ev->down.total, (long int) ev->down.now,
			  (long int) ev->up.total, (long int) ev->up.now) != 0)
       {
	  _job_list = eina_list_remove(_job_list, job);
	  _ecore_file_download_abort(job);
       }

   return 0;
}

Ecore_File_Download_Job *
_ecore_file_download_curl(const char *url, const char *dst,
			  void (*completion_cb)(void *data, const char *file,
						int status),
			  int (*progress_cb)(void *data, const char *file,
					     long int dltotal, long int dlnow,
					     long int ultotal, long int ulnow),
			  void *data)
{
   Ecore_File_Download_Job *job;

   job = calloc(1, sizeof(Ecore_File_Download_Job));
   if (!job) return NULL;

   ECORE_MAGIC_SET(job, ECORE_MAGIC_FILE_DOWNLOAD_JOB);

   job->file = fopen(dst, "wb");
   if (!job->file)
     {
	free(job);
	return NULL;
     }
   job->url_con = ecore_con_url_new(url);
   if (!job->url_con)
     {
	fclose(job->file);
	free(job);
	return NULL;
     }

   ecore_con_url_fd_set(job->url_con, fileno(job->file));
   ecore_con_url_data_set(job->url_con, data);

   job->dst = strdup(dst);

   job->completion_cb = completion_cb;
   job->progress_cb = progress_cb;
   _job_list = eina_list_append(_job_list, job);

   ecore_con_url_send(job->url_con, NULL, 0, NULL);

   return job;
}
#endif

static void
_ecore_file_download_abort(Ecore_File_Download_Job *job)
{
#ifdef HAVE_CURL
   ecore_con_url_destroy(job->url_con);
#endif  
   fclose(job->file);
   free(job->dst);
   free(job);
}