]>
Commit | Line | Data |
---|---|---|
a3697549 | 1 | /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ |
85611cd9 GB |
2 | /* |
3 | * viking -- GPS Data and Topo Analyzer, Explorer, and Manager | |
4 | * | |
5 | * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net> | |
a482007a | 6 | * Copyright (C) 2007, Guilhem Bonnefille <guilhem.bonnefille@gmail.com> |
a3697549 | 7 | * Copyright (C) 2013, Rob Norris <rw_norris@hotmail.com> |
85611cd9 GB |
8 | * |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; either version 2 of the License, or | |
12 | * (at your option) any later version. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; if not, write to the Free Software | |
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
22 | * | |
23 | */ | |
24 | ||
3292ba8b GB |
25 | #ifdef HAVE_CONFIG_H |
26 | #include "config.h" | |
27 | #endif | |
28 | ||
932f8f22 | 29 | #include <stdio.h> |
6e78a423 | 30 | #include <ctype.h> |
6a4a29aa | 31 | #include <errno.h> |
6e78a423 | 32 | #include <string.h> |
7de36baf | 33 | #ifdef HAVE_SYS_TYPES_H |
6a4a29aa | 34 | #include <sys/types.h> |
7de36baf GB |
35 | #endif |
36 | #ifdef HAVE_UTIME_H | |
6a4a29aa | 37 | #include <utime.h> |
7de36baf | 38 | #endif |
f83131b9 MA |
39 | #include <glib.h> |
40 | #include <glib/gstdio.h> | |
4c77d5e0 | 41 | #include <glib/gi18n.h> |
932f8f22 | 42 | |
5c1cf59f | 43 | #include "file_magic.h" |
a3697549 | 44 | #include "compression.h" |
85611cd9 | 45 | #include "download.h" |
3292ba8b | 46 | |
3292ba8b | 47 | #include "curl_download.h" |
6693f5f9 GB |
48 | #include "preferences.h" |
49 | #include "globals.h" | |
fc6640a9 | 50 | #include "vik_compat.h" |
85611cd9 | 51 | |
388cf5a4 | 52 | static gboolean check_file_first_line(FILE* f, gchar *patterns[]) |
6e78a423 | 53 | { |
533bbf34 MA |
54 | gchar **s; |
55 | gchar *bp; | |
6e78a423 | 56 | fpos_t pos; |
533bbf34 | 57 | gchar buf[33]; |
6e78a423 | 58 | size_t nr; |
6e78a423 | 59 | |
c44594ee | 60 | memset(buf, 0, sizeof(buf)); |
fd437981 RN |
61 | if ( !fgetpos(f, &pos) ) |
62 | return FALSE; | |
6e78a423 QT |
63 | rewind(f); |
64 | nr = fread(buf, 1, sizeof(buf) - 1, f); | |
fd437981 RN |
65 | if ( !fgetpos(f, &pos) ) |
66 | return FALSE; | |
6e78a423 QT |
67 | for (bp = buf; (bp < (buf + sizeof(buf) - 1)) && (nr > (bp - buf)); bp++) { |
68 | if (!(isspace(*bp))) | |
69 | break; | |
70 | } | |
71 | if ((bp >= (buf + sizeof(buf) -1)) || ((bp - buf) >= nr)) | |
1ac37c09 | 72 | return FALSE; |
388cf5a4 | 73 | for (s = patterns; *s; s++) { |
1918a993 | 74 | if (strncasecmp(*s, bp, strlen(*s)) == 0) |
1ac37c09 | 75 | return TRUE; |
6e78a423 | 76 | } |
1ac37c09 GB |
77 | return FALSE; |
78 | } | |
79 | ||
388cf5a4 GB |
80 | gboolean a_check_html_file(FILE* f) |
81 | { | |
82 | gchar * html_str[] = { | |
83 | "<html", | |
84 | "<!DOCTYPE html", | |
85 | "<head", | |
86 | "<title", | |
87 | NULL | |
88 | }; | |
89 | ||
90 | return check_file_first_line(f, html_str); | |
91 | } | |
92 | ||
1ac37c09 GB |
93 | gboolean a_check_map_file(FILE* f) |
94 | { | |
388cf5a4 | 95 | /* FIXME no more true since a_check_kml_file */ |
1ac37c09 | 96 | return !a_check_html_file(f); |
6e78a423 QT |
97 | } |
98 | ||
ae941b4c HMJ |
99 | gboolean a_check_kml_file(FILE* f) |
100 | { | |
388cf5a4 | 101 | gchar * kml_str[] = { |
ae941b4c HMJ |
102 | "<?xml", |
103 | NULL | |
104 | }; | |
105 | ||
388cf5a4 | 106 | return check_file_first_line(f, kml_str); |
ae941b4c HMJ |
107 | } |
108 | ||
4b992365 GB |
109 | static GList *file_list = NULL; |
110 | static GMutex *file_list_mutex = NULL; | |
111 | ||
6693f5f9 | 112 | /* spin button scales */ |
32dfea86 RN |
113 | static VikLayerParamScale params_scales[] = { |
114 | {1, 365, 1, 0}, /* download_tile_age */ | |
6693f5f9 GB |
115 | }; |
116 | ||
32dfea86 RN |
117 | static VikLayerParamData convert_to_display ( VikLayerParamData value ) |
118 | { | |
119 | // From seconds into days | |
120 | return VIK_LPD_UINT ( value.u / 86400 ); | |
121 | } | |
122 | ||
123 | static VikLayerParamData convert_to_internal ( VikLayerParamData value ) | |
124 | { | |
125 | // From days into seconds | |
126 | return VIK_LPD_UINT ( 86400 * value.u ); | |
127 | } | |
128 | ||
6693f5f9 | 129 | static VikLayerParam prefs[] = { |
32dfea86 | 130 | { VIK_LAYER_NUM_TYPES, VIKING_PREFERENCES_NAMESPACE "download_tile_age", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Tile age (days):"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[0], NULL, NULL, NULL, convert_to_display, convert_to_internal }, |
6693f5f9 GB |
131 | }; |
132 | ||
4b992365 GB |
133 | void a_download_init (void) |
134 | { | |
6693f5f9 | 135 | VikLayerParamData tmp; |
32dfea86 | 136 | tmp.u = VIK_CONFIG_DEFAULT_TILE_AGE / 86400; // Now in days |
6693f5f9 | 137 | a_preferences_register(prefs, tmp, VIKING_PREFERENCES_GROUP_KEY); |
fc6640a9 | 138 | file_list_mutex = vik_mutex_new(); |
e3da2277 | 139 | } |
6693f5f9 | 140 | |
e3da2277 RN |
141 | void a_download_uninit (void) |
142 | { | |
143 | vik_mutex_free(file_list_mutex); | |
4b992365 GB |
144 | } |
145 | ||
146 | static gboolean lock_file(const char *fn) | |
147 | { | |
148 | gboolean locked = FALSE; | |
149 | g_mutex_lock(file_list_mutex); | |
2894744e | 150 | if (g_list_find_custom(file_list, fn, (GCompareFunc)g_strcmp0) == NULL) |
4b992365 GB |
151 | { |
152 | // The filename is not yet locked | |
153 | file_list = g_list_append(file_list, (gpointer)fn), | |
154 | locked = TRUE; | |
155 | } | |
156 | g_mutex_unlock(file_list_mutex); | |
157 | return locked; | |
158 | } | |
159 | ||
160 | static void unlock_file(const char *fn) | |
161 | { | |
162 | g_mutex_lock(file_list_mutex); | |
163 | file_list = g_list_remove(file_list, (gconstpointer)fn); | |
164 | g_mutex_unlock(file_list_mutex); | |
165 | } | |
166 | ||
feef2120 RN |
167 | /** |
168 | * Unzip a file - replacing the file with the unzipped contents of the self | |
169 | */ | |
a3697549 RN |
170 | static void uncompress_zip ( gchar *name ) |
171 | { | |
172 | GError *error = NULL; | |
173 | GMappedFile *mf; | |
174 | ||
175 | if ((mf = g_mapped_file_new ( name, FALSE, &error )) == NULL) { | |
176 | g_critical(_("Couldn't map file %s: %s"), name, error->message); | |
177 | g_error_free(error); | |
178 | return; | |
179 | } | |
180 | gchar *file_contents = g_mapped_file_get_contents ( mf ); | |
181 | ||
182 | void *unzip_mem = NULL; | |
183 | gulong ucsize; | |
184 | ||
185 | if ((unzip_mem = unzip_file (file_contents, &ucsize)) == NULL) { | |
186 | g_mapped_file_unref ( mf ); | |
187 | return; | |
188 | } | |
189 | ||
feef2120 | 190 | // This overwrites any previous file contents |
a3697549 RN |
191 | if ( ! g_file_set_contents ( name, unzip_mem, ucsize, &error ) ) { |
192 | g_critical ( "Couldn't write file '%s', because of %s", name, error->message ); | |
193 | g_error_free ( error ); | |
194 | } | |
195 | } | |
196 | ||
197 | /** | |
198 | * a_try_decompress_file: | |
199 | * @name: The potentially compressed filename | |
200 | * | |
201 | * Perform magic to decide how which type of decompression to attempt | |
202 | */ | |
203 | void a_try_decompress_file (gchar *name) | |
204 | { | |
5c1cf59f | 205 | if ( file_magic_check (name, "application/zip", ".zip") ) { |
a3697549 RN |
206 | uncompress_zip ( name ); |
207 | } | |
5c1cf59f | 208 | else if ( file_magic_check (name, "application/x-bzip2", ".bz2") ) { |
a3697549 | 209 | gchar* bz2_name = uncompress_bzip2 ( name ); |
7184955f RN |
210 | if ( bz2_name ) { |
211 | if ( g_remove ( name ) ) | |
212 | g_critical ("%s: remove file failed [%s]", __FUNCTION__, name ); | |
213 | if ( g_rename (bz2_name, name) ) | |
214 | g_critical ("%s: file rename failed [%s] to [%s]", __FUNCTION__, bz2_name, name ); | |
15f1e9b4 | 215 | g_free ( bz2_name ); |
7184955f | 216 | } |
a3697549 | 217 | } |
a3697549 RN |
218 | } |
219 | ||
fed82438 SW |
220 | #define VIKING_ETAG_XATTR "xattr::viking.etag" |
221 | ||
686baff0 | 222 | static gboolean get_etag_xattr(const char *fn, CurlDownloadOptions *cdo) |
fed82438 SW |
223 | { |
224 | gboolean result = FALSE; | |
225 | GFileInfo *fileinfo; | |
226 | GFile *file; | |
227 | ||
228 | file = g_file_new_for_path(fn); | |
229 | fileinfo = g_file_query_info(file, VIKING_ETAG_XATTR, G_FILE_QUERY_INFO_NONE, NULL, NULL); | |
230 | if (fileinfo) { | |
231 | const char *etag = g_file_info_get_attribute_string(fileinfo, VIKING_ETAG_XATTR); | |
232 | if (etag) { | |
686baff0 RN |
233 | cdo->etag = g_strdup(etag); |
234 | result = !!cdo->etag; | |
fed82438 SW |
235 | } |
236 | g_object_unref(fileinfo); | |
237 | } | |
238 | g_object_unref(file); | |
239 | ||
240 | if (result) | |
686baff0 | 241 | g_debug("%s: Get etag (xattr) from %s: %s", __FUNCTION__, fn, cdo->etag); |
fed82438 SW |
242 | |
243 | return result; | |
244 | } | |
245 | ||
686baff0 | 246 | static gboolean get_etag_file(const char *fn, CurlDownloadOptions *cdo) |
fed82438 SW |
247 | { |
248 | gboolean result = FALSE; | |
249 | gchar *etag_filename; | |
250 | ||
251 | etag_filename = g_strdup_printf("%s.etag", fn); | |
252 | if (etag_filename) { | |
686baff0 | 253 | result = g_file_get_contents(etag_filename, &cdo->etag, NULL, NULL); |
fed82438 SW |
254 | g_free(etag_filename); |
255 | } | |
256 | ||
257 | if (result) | |
686baff0 | 258 | g_debug("%s: Get etag (file) from %s: %s", __FUNCTION__, fn, cdo->etag); |
fed82438 SW |
259 | |
260 | return result; | |
261 | } | |
262 | ||
686baff0 | 263 | static void get_etag(const char *fn, CurlDownloadOptions *cdo) |
fed82438 SW |
264 | { |
265 | /* first try to get etag from xattr, then fall back to plain file */ | |
686baff0 | 266 | if (!get_etag_xattr(fn, cdo) && !get_etag_file(fn, cdo)) { |
fed82438 SW |
267 | g_debug("%s: Failed to get etag from %s", __FUNCTION__, fn); |
268 | return; | |
269 | } | |
270 | ||
271 | /* check if etag is short enough */ | |
686baff0 RN |
272 | if (strlen(cdo->etag) > 100) { |
273 | g_free(cdo->etag); | |
274 | cdo->etag = NULL; | |
fed82438 SW |
275 | } |
276 | ||
277 | /* TODO: should check that etag is a valid string */ | |
278 | } | |
279 | ||
686baff0 | 280 | static gboolean set_etag_xattr(const char *fn, CurlDownloadOptions *cdo) |
fed82438 SW |
281 | { |
282 | gboolean result = FALSE; | |
283 | GFile *file; | |
284 | ||
285 | file = g_file_new_for_path(fn); | |
686baff0 | 286 | result = g_file_set_attribute_string(file, VIKING_ETAG_XATTR, cdo->new_etag, G_FILE_QUERY_INFO_NONE, NULL, NULL); |
fed82438 SW |
287 | g_object_unref(file); |
288 | ||
289 | if (result) | |
686baff0 | 290 | g_debug("%s: Set etag (xattr) on %s: %s", __FUNCTION__, fn, cdo->new_etag); |
fed82438 SW |
291 | |
292 | return result; | |
293 | } | |
294 | ||
686baff0 | 295 | static gboolean set_etag_file(const char *fn, CurlDownloadOptions *cdo) |
fed82438 SW |
296 | { |
297 | gboolean result = FALSE; | |
298 | gchar *etag_filename; | |
299 | ||
300 | etag_filename = g_strdup_printf("%s.etag", fn); | |
301 | if (etag_filename) { | |
686baff0 | 302 | result = g_file_set_contents(etag_filename, cdo->new_etag, -1, NULL); |
fed82438 SW |
303 | g_free(etag_filename); |
304 | } | |
305 | ||
306 | if (result) | |
686baff0 | 307 | g_debug("%s: Set etag (file) on %s: %s", __FUNCTION__, fn, cdo->new_etag); |
fed82438 SW |
308 | |
309 | return result; | |
310 | } | |
311 | ||
686baff0 | 312 | static void set_etag(const char *fn, const char *fntmp, CurlDownloadOptions *cdo) |
fed82438 SW |
313 | { |
314 | /* first try to store etag in extended attribute, then fall back to plain file */ | |
686baff0 | 315 | if (!set_etag_xattr(fntmp, cdo) && !set_etag_file(fn, cdo)) { |
fed82438 SW |
316 | g_debug("%s: Failed to set etag on %s", __FUNCTION__, fn); |
317 | } | |
318 | } | |
319 | ||
686baff0 | 320 | static DownloadResult_t download( const char *hostname, const char *uri, const char *fn, DownloadFileOptions *options, gboolean ftp, void *handle) |
932f8f22 GB |
321 | { |
322 | FILE *f; | |
533bbf34 | 323 | gchar *tmpfilename; |
1ac37c09 | 324 | gboolean failure = FALSE; |
686baff0 | 325 | CurlDownloadOptions cdo = {0, NULL, NULL}; |
932f8f22 GB |
326 | |
327 | /* Check file */ | |
45acf79e | 328 | if ( g_file_test ( fn, G_FILE_TEST_EXISTS ) == TRUE ) |
932f8f22 | 329 | { |
8853eed9 JJ |
330 | if (options == NULL || (!options->check_file_server_time && |
331 | !options->use_etag)) { | |
332 | /* Nothing to do as file already exists and we don't want to check server */ | |
4e815e90 | 333 | return DOWNLOAD_NOT_REQUIRED; |
6a4a29aa | 334 | } |
8853eed9 | 335 | |
57ecf9cb JJ |
336 | time_t tile_age = a_preferences_get(VIKING_PREFERENCES_NAMESPACE "download_tile_age")->u; |
337 | /* Get the modified time of this file */ | |
603b6b7e | 338 | GStatBuf buf; |
fd437981 | 339 | (void)g_stat ( fn, &buf ); |
57ecf9cb JJ |
340 | time_t file_time = buf.st_mtime; |
341 | if ( (time(NULL) - file_time) < tile_age ) { | |
342 | /* File cache is too recent, so return */ | |
4e815e90 | 343 | return DOWNLOAD_NOT_REQUIRED; |
57ecf9cb JJ |
344 | } |
345 | ||
e69ac989 | 346 | if (options != NULL && options->check_file_server_time) { |
686baff0 | 347 | cdo.time_condition = file_time; |
6a4a29aa | 348 | } |
e69ac989 | 349 | if (options != NULL && options->use_etag) { |
686baff0 | 350 | get_etag(fn, &cdo); |
55246377 | 351 | } |
f91cc826 | 352 | |
932f8f22 | 353 | } else { |
a1618d62 | 354 | gchar *dir = g_path_get_dirname ( fn ); |
5e4cce8f RN |
355 | if ( g_mkdir_with_parents ( dir , 0777 ) != 0) |
356 | g_warning ("%s: Failed to mkdir %s", __FUNCTION__, dir ); | |
a1618d62 | 357 | g_free ( dir ); |
3335ae4e EB |
358 | } |
359 | ||
4dc72a1d RN |
360 | // Early test for valid hostname & uri to avoid unnecessary tmp file |
361 | if ( !hostname && !uri ) { | |
362 | g_warning ( "%s: Parameter error - neither hostname nor uri defined", __FUNCTION__ ); | |
363 | return DOWNLOAD_PARAMETERS_ERROR; | |
364 | } | |
365 | ||
3335ae4e | 366 | tmpfilename = g_strdup_printf("%s.tmp", fn); |
4b992365 GB |
367 | if (!lock_file ( tmpfilename ) ) |
368 | { | |
369 | g_debug("%s: Couldn't take lock on temporary file \"%s\"\n", __FUNCTION__, tmpfilename); | |
370 | g_free ( tmpfilename ); | |
9137c580 | 371 | if (options->use_etag) |
686baff0 | 372 | g_free ( cdo.etag ); |
4e815e90 | 373 | return DOWNLOAD_FILE_WRITE_ERROR; |
4b992365 GB |
374 | } |
375 | f = g_fopen ( tmpfilename, "w+b" ); /* truncate file and open it */ | |
3335ae4e | 376 | if ( ! f ) { |
4b992365 | 377 | g_warning("Couldn't open temporary file \"%s\": %s", tmpfilename, g_strerror(errno)); |
3335ae4e | 378 | g_free ( tmpfilename ); |
9137c580 | 379 | if (options->use_etag) |
686baff0 | 380 | g_free ( cdo.etag ); |
4e815e90 | 381 | return DOWNLOAD_FILE_WRITE_ERROR; |
932f8f22 GB |
382 | } |
383 | ||
384 | /* Call the backend function */ | |
4dc72a1d | 385 | CURL_download_t ret = curl_download_get_url ( hostname, uri, f, options, ftp, &cdo, handle ); |
6a4a29aa | 386 | |
4e815e90 RN |
387 | DownloadResult_t result = DOWNLOAD_SUCCESS; |
388 | ||
389 | if (ret != CURL_DOWNLOAD_NO_ERROR && ret != CURL_DOWNLOAD_NO_NEWER_FILE) { | |
1ac37c09 GB |
390 | g_debug("%s: download failed: curl_download_get_url=%d", __FUNCTION__, ret); |
391 | failure = TRUE; | |
4e815e90 | 392 | result = DOWNLOAD_HTTP_ERROR; |
1ac37c09 GB |
393 | } |
394 | ||
395 | if (!failure && options != NULL && options->check_file != NULL && ! options->check_file(f)) { | |
396 | g_debug("%s: file content checking failed", __FUNCTION__); | |
397 | failure = TRUE; | |
4e815e90 | 398 | result = DOWNLOAD_CONTENT_ERROR; |
1ac37c09 | 399 | } |
932f8f22 | 400 | |
1ec35593 MA |
401 | fclose ( f ); |
402 | f = NULL; | |
403 | ||
1ac37c09 | 404 | if (failure) |
932f8f22 | 405 | { |
4258f4e2 | 406 | g_warning(_("Download error: %s"), fn); |
c5ecc990 RN |
407 | if ( g_remove ( tmpfilename ) != 0 ) |
408 | g_warning( ("Failed to remove: %s"), tmpfilename); | |
4b992365 | 409 | unlock_file ( tmpfilename ); |
3335ae4e | 410 | g_free ( tmpfilename ); |
e69ac989 | 411 | if ( options != NULL && options->use_etag ) { |
686baff0 RN |
412 | g_free ( cdo.etag ); |
413 | g_free ( cdo.new_etag ); | |
55246377 | 414 | } |
4e815e90 | 415 | return result; |
932f8f22 GB |
416 | } |
417 | ||
4e815e90 | 418 | if (ret == CURL_DOWNLOAD_NO_NEWER_FILE) { |
85e9e947 | 419 | (void)g_remove ( tmpfilename ); |
73e61a6e RN |
420 | // update mtime of local copy |
421 | // Not security critical, thus potential Time of Check Time of Use race condition is not bad | |
422 | // coverity[toctou] | |
423 | if ( g_utime ( fn, NULL ) != 0 ) | |
424 | g_warning ( "%s couldn't set time on: %s", __FUNCTION__, fn ); | |
4945e425 | 425 | } else { |
0e818e49 SW |
426 | if ( options != NULL && options->convert_file ) |
427 | options->convert_file ( tmpfilename ); | |
428 | ||
429 | if ( options != NULL && options->use_etag ) { | |
686baff0 | 430 | if ( cdo.new_etag ) { |
0e818e49 | 431 | /* server returned an etag value */ |
686baff0 | 432 | set_etag(fn, tmpfilename, &cdo); |
0e818e49 SW |
433 | } |
434 | } | |
435 | ||
4bdc96fc RN |
436 | /* move completely-downloaded file to permanent location */ |
437 | if ( g_rename ( tmpfilename, fn ) ) | |
438 | g_warning ("%s: file rename failed [%s] to [%s]", __FUNCTION__, tmpfilename, fn ); | |
4945e425 | 439 | } |
4b992365 | 440 | unlock_file ( tmpfilename ); |
6a4a29aa | 441 | g_free ( tmpfilename ); |
1ec35593 | 442 | |
e69ac989 | 443 | if ( options != NULL && options->use_etag ) { |
686baff0 RN |
444 | g_free ( cdo.etag ); |
445 | g_free ( cdo.new_etag ); | |
55246377 | 446 | } |
4e815e90 | 447 | return DOWNLOAD_SUCCESS; |
932f8f22 GB |
448 | } |
449 | ||
4e815e90 RN |
450 | /** |
451 | * uri: like "/uri.html?whatever" | |
452 | * only reason for the "wrapper" is so we can do redirects. | |
453 | */ | |
686baff0 | 454 | DownloadResult_t a_http_download_get_url ( const char *hostname, const char *uri, const char *fn, DownloadFileOptions *opt, void *handle ) |
85611cd9 | 455 | { |
825413ba | 456 | return download ( hostname, uri, fn, opt, FALSE, handle ); |
0c1044e9 EB |
457 | } |
458 | ||
686baff0 | 459 | DownloadResult_t a_ftp_download_get_url ( const char *hostname, const char *uri, const char *fn, DownloadFileOptions *opt, void *handle ) |
0c1044e9 | 460 | { |
825413ba SW |
461 | return download ( hostname, uri, fn, opt, TRUE, handle ); |
462 | } | |
463 | ||
464 | void * a_download_handle_init () | |
465 | { | |
466 | return curl_download_handle_init (); | |
467 | } | |
468 | ||
469 | void a_download_handle_cleanup ( void *handle ) | |
470 | { | |
471 | curl_download_handle_cleanup ( handle ); | |
85611cd9 | 472 | } |
e09b94fe RN |
473 | |
474 | /** | |
475 | * a_download_url_to_tmp_file: | |
476 | * @uri: The URI (Uniform Resource Identifier) | |
477 | * @options: Download options (maybe NULL) | |
478 | * | |
479 | * returns name of the temporary file created - NULL if unsuccessful | |
480 | * this string needs to be freed once used | |
481 | * the file needs to be removed once used | |
482 | */ | |
686baff0 | 483 | gchar *a_download_uri_to_tmp_file ( const gchar *uri, DownloadFileOptions *options ) |
e09b94fe RN |
484 | { |
485 | FILE *tmp_file; | |
486 | int tmp_fd; | |
487 | gchar *tmpname; | |
488 | ||
489 | if ( (tmp_fd = g_file_open_tmp ("viking-download.XXXXXX", &tmpname, NULL)) == -1 ) { | |
490 | g_critical (_("couldn't open temp file")); | |
491 | return NULL; | |
492 | } | |
493 | ||
494 | tmp_file = fdopen(tmp_fd, "r+"); | |
86b25a6c RN |
495 | if ( !tmp_file ) |
496 | return NULL; | |
e09b94fe RN |
497 | |
498 | if ( curl_download_uri ( uri, tmp_file, options, NULL, NULL ) ) { | |
499 | // error | |
500 | fclose ( tmp_file ); | |
85e9e947 | 501 | (void)g_remove ( tmpname ); |
e09b94fe RN |
502 | g_free ( tmpname ); |
503 | return NULL; | |
504 | } | |
505 | fclose ( tmp_file ); | |
506 | ||
507 | return tmpname; | |
508 | } |