Revert "update: rename the variables so that it matches their current purpose"
[vlc.git] / src / misc / update.c
1 /*****************************************************************************
2  * update.c: VLC update checking and downloading
3  *****************************************************************************
4  * Copyright © 2005-2008 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
8  *          Rémi Duraffort <ivoire at via.ecp.fr>
9             Rafaël Carré <funman@videolanorg>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either release 2 of the License, or
14  * (at your option) any later release.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 /**
27  *   \file
28  *   This file contains functions related to VLC update management
29  */
30
31 /*****************************************************************************
32  * Preamble
33  *****************************************************************************/
34
35 #ifdef HAVE_CONFIG_H
36 # include "config.h"
37 #endif
38 #ifdef HAVE_SYS_STAT_H
39 #   include <sys/stat.h>
40 #endif
41
42 #include <vlc_common.h>
43 #include <vlc_update.h>
44
45 #ifdef UPDATE_CHECK
46
47 #include <assert.h>
48
49 #include <vlc_pgpkey.h>
50 #include <vlc_stream.h>
51 #include <vlc_strings.h>
52 #include <vlc_charset.h>
53 #include <vlc_dialog.h>
54
55 #include <gcrypt.h>
56 #include <vlc_gcrypt.h>
57
58 #include "update.h"
59 #include "../libvlc.h"
60
61 /*****************************************************************************
62  * Misc defines
63  *****************************************************************************/
64
65 /*
66  * Here is the format of these "status files" :
67  * First line is the last version: "X.Y.Ze" where:
68  *      * X is the major number
69  *      * Y is the minor number
70  *      * Z is the revision number
71  *      * e is an OPTIONAL extra letter
72  *      * AKA "0.8.6d" or "0.9.0"
73  * Second line is an url of the binary for this last version
74  * Remaining text is a required description of the update
75  */
76
77 #if defined( UNDER_CE )
78 #   define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-ce"
79 #elif defined( WIN32 )
80 #   define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-win-x86"
81 #elif defined( __APPLE__ )
82 #   if defined( __powerpc__ ) || defined( __ppc__ ) || defined( __ppc64__ )
83 #       define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-mac-ppc"
84 #   else
85 #       define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-mac-x86"
86 #   endif
87 #elif defined( SYS_BEOS )
88 #       define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-beos-x86"
89 #else
90 #   define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status"
91 #endif
92
93
94 /*****************************************************************************
95  * Local Prototypes
96  *****************************************************************************/
97 static void EmptyRelease( update_t *p_update );
98 static bool GetUpdateFile( update_t *p_update );
99 static char * size_str( long int l_size );
100
101
102
103 /*****************************************************************************
104  * Update_t functions
105  *****************************************************************************/
106
107 /**
108  * Create a new update VLC struct
109  *
110  * \param p_this the calling vlc_object
111  * \return pointer to new update_t or NULL
112  */
113 update_t *__update_New( vlc_object_t *p_this )
114 {
115     update_t *p_update;
116     assert( p_this );
117
118     p_update = (update_t *)malloc( sizeof( update_t ) );
119     if( !p_update ) return NULL;
120
121     vlc_mutex_init( &p_update->lock );
122
123     p_update->p_libvlc = p_this->p_libvlc;
124
125     p_update->release.psz_url = NULL;
126     p_update->release.psz_desc = NULL;
127
128     p_update->p_download = NULL;
129     p_update->p_check = NULL;
130
131     p_update->p_pkey = NULL;
132     vlc_gcrypt_init();
133
134     return p_update;
135 }
136
137 /**
138  * Delete an update_t struct
139  *
140  * \param p_update update_t* pointer
141  * \return nothing
142  */
143 void update_Delete( update_t *p_update )
144 {
145     assert( p_update );
146
147     if( p_update->p_check )
148     {
149         assert( !p_update->p_download );
150         vlc_object_kill( p_update->p_check );
151         vlc_thread_join( p_update->p_check );
152         vlc_object_release( p_update->p_check );
153     }
154     else if( p_update->p_download )
155     {
156         vlc_object_kill( p_update->p_download );
157         vlc_thread_join( p_update->p_download );
158         vlc_object_release( p_update->p_download );
159     }
160
161     vlc_mutex_destroy( &p_update->lock );
162
163     free( p_update->release.psz_url );
164     free( p_update->release.psz_desc );
165     free( p_update->p_pkey );
166
167     free( p_update );
168 }
169
170 /**
171  * Empty the release struct
172  *
173  * \param p_update update_t* pointer
174  * \return nothing
175  */
176 static void EmptyRelease( update_t *p_update )
177 {
178     p_update->release.i_major = 0;
179     p_update->release.i_minor = 0;
180     p_update->release.i_revision = 0;
181
182     FREENULL( p_update->release.psz_url );
183     FREENULL( p_update->release.psz_desc );
184 }
185
186 /**
187  * Get the update file and parse it
188  * p_update has to be locked when calling this function
189  *
190  * \param p_update pointer to update struct
191  * \return true if the update is valid and authenticated
192  */
193 static bool GetUpdateFile( update_t *p_update )
194 {
195     stream_t *p_stream = NULL;
196     int i_major = 0;
197     int i_minor = 0;
198     int i_revision = 0;
199     unsigned char extra;
200     char *psz_version_line = NULL;
201
202     p_stream = stream_UrlNew( p_update->p_libvlc, UPDATE_VLC_STATUS_URL );
203     if( !p_stream )
204     {
205         msg_Err( p_update->p_libvlc, "Failed to open %s for reading",
206                  UPDATE_VLC_STATUS_URL );
207         goto error;
208     }
209
210     /* Start reading the status file */
211     if( !( psz_version_line = stream_ReadLine( p_stream ) ) )
212     {
213         msg_Err( p_update->p_libvlc, "Update file %s is corrupted : missing version",
214                  UPDATE_VLC_STATUS_URL );
215         goto error;
216     }
217
218     /* first line : version number */
219     p_update->release.extra = 0;
220     switch( sscanf( psz_version_line, "%i.%i.%i%c",
221                     &i_major, &i_minor, &i_revision, &extra ) )
222     {
223         case 4:
224             p_update->release.extra = extra;
225         case 3:
226             p_update->release.i_major = i_major;
227             p_update->release.i_minor = i_minor;
228             p_update->release.i_revision = i_revision;
229             break;
230         default:
231             msg_Err( p_update->p_libvlc, "Update version false formated" );
232             goto error;
233     }
234
235     /* second line : URL */
236     if( !( p_update->release.psz_url = stream_ReadLine( p_stream ) ) )
237     {
238         msg_Err( p_update->p_libvlc, "Update file %s is corrupted : URL missing",
239                  UPDATE_VLC_STATUS_URL );
240         goto error;
241     }
242
243     /* Remaining data : description */
244     int i_read = stream_Size( p_stream ) - stream_Tell( p_stream );
245     if( i_read <= 0 )
246     {
247         msg_Err( p_update->p_libvlc,
248                 "Update file %s is corrupted: description missing",
249                 UPDATE_VLC_STATUS_URL );
250         goto error;
251     }
252
253     p_update->release.psz_desc = (char*) malloc( i_read + 1 );
254     if( !p_update->release.psz_desc )
255         goto error;
256
257     if( stream_Read( p_stream, p_update->release.psz_desc, i_read ) != i_read )
258     {
259         msg_Err( p_update->p_libvlc, "Couldn't download update file %s",
260                 UPDATE_VLC_STATUS_URL );
261         goto error;
262     }
263     p_update->release.psz_desc[i_read] = '\0';
264
265     stream_Delete( p_stream );
266     p_stream = NULL;
267
268     /* Now that we know the status is valid, we must download its signature
269      * to authenticate it */
270     signature_packet_t sign;
271     if( download_signature( VLC_OBJECT( p_update->p_libvlc ), &sign,
272             UPDATE_VLC_STATUS_URL ) != VLC_SUCCESS )
273     {
274         msg_Err( p_update->p_libvlc, "Couldn't download signature of status file" );
275         goto error;
276     }
277
278     if( sign.type != BINARY_SIGNATURE && sign.type != TEXT_SIGNATURE )
279     {
280         msg_Err( p_update->p_libvlc, "Invalid signature type" );
281         goto error;
282     }
283
284     p_update->p_pkey = (public_key_t*)malloc( sizeof( public_key_t ) );
285     if( !p_update->p_pkey )
286         goto error;
287
288     if( parse_public_key( videolan_public_key, sizeof( videolan_public_key ),
289                         p_update->p_pkey, NULL ) != VLC_SUCCESS )
290     {
291         msg_Err( p_update->p_libvlc, "Couldn't parse embedded public key, something went really wrong..." );
292         FREENULL( p_update->p_pkey );
293         goto error;
294     }
295
296     memcpy( p_update->p_pkey->longid, videolan_public_key_longid, 8 );
297
298     if( memcmp( sign.issuer_longid, p_update->p_pkey->longid , 8 ) != 0 )
299     {
300         msg_Dbg( p_update->p_libvlc, "Need to download the GPG key" );
301         public_key_t *p_new_pkey = download_key(
302                 VLC_OBJECT(p_update->p_libvlc),
303                 sign.issuer_longid, videolan_public_key_longid );
304         if( !p_new_pkey )
305         {
306             msg_Err( p_update->p_libvlc, "Couldn't download GPG key" );
307             FREENULL( p_update->p_pkey );
308             goto error;
309         }
310
311         uint8_t *p_hash = hash_sha1_from_public_key( p_new_pkey );
312         if( !p_hash )
313         {
314             msg_Err( p_update->p_libvlc, "Failed to hash signature" );
315             free( p_new_pkey );
316             FREENULL( p_update->p_pkey );
317             goto error;
318         }
319
320         if( verify_signature( p_new_pkey->sig.r, p_new_pkey->sig.s,
321                     &p_update->p_pkey->key, p_hash ) == VLC_SUCCESS )
322         {
323             free( p_hash );
324             msg_Info( p_update->p_libvlc, "Key authenticated" );
325             free( p_update->p_pkey );
326             p_update->p_pkey = p_new_pkey;
327         }
328         else
329         {
330             free( p_hash );
331             msg_Err( p_update->p_libvlc, "Key signature invalid !\n" );
332             goto error;
333         }
334     }
335
336     /* FIXME : read the status file all at once instead of line per line */
337     char *psz_text;
338     if( asprintf( &psz_text, "%s\n%s\n%s", psz_version_line,
339                 p_update->release.psz_url, p_update->release.psz_desc ) == -1 )
340     {
341         goto error;
342     }
343     FREENULL( psz_version_line );
344
345     uint8_t *p_hash = hash_sha1_from_text( psz_text, &sign );
346     if( !p_hash )
347     {
348         msg_Warn( p_update->p_libvlc, "Can't compute SHA1 hash for status file" );
349         goto error;
350     }
351
352     else if( p_hash[0] != sign.hash_verification[0] ||
353         p_hash[1] != sign.hash_verification[1] )
354     {
355         msg_Warn( p_update->p_libvlc, "Bad SHA1 hash for status file" );
356         goto error;
357     }
358
359     else if( verify_signature( sign.r, sign.s, &p_update->p_pkey->key, p_hash )
360             != VLC_SUCCESS )
361     {
362         msg_Err( p_update->p_libvlc, "BAD SIGNATURE for status file" );
363         goto error;
364     }
365
366     else
367     {
368         msg_Info( p_update->p_libvlc, "Status file authenticated" );
369         return true;
370     }
371
372 error:
373     if( p_stream )
374         stream_Delete( p_stream );
375     free( psz_version_line );
376     return false;
377 }
378
379 static void* update_CheckReal( vlc_object_t *p_this );
380
381 /**
382  * Check for updates
383  *
384  * \param p_update pointer to update struct
385  * \param pf_callback pointer to a function to call when the update_check is finished
386  * \param p_data pointer to some datas to give to the callback
387  * \returns nothing
388  */
389 void update_Check( update_t *p_update, void (*pf_callback)( void*, bool ), void *p_data )
390 {
391     assert( p_update );
392
393     // If the object already exist, destroy it
394     if( p_update->p_check )
395     {
396         vlc_object_kill( p_update->p_check );
397         vlc_thread_join( p_update->p_check );
398         vlc_object_release( p_update->p_check );
399     }
400
401     update_check_thread_t *p_uct =
402         vlc_custom_create( p_update->p_libvlc, sizeof( *p_uct ),
403                            VLC_OBJECT_GENERIC, "update check" );
404     if( !p_uct ) return;
405
406     p_uct->p_update = p_update;
407     p_update->p_check = p_uct;
408     p_uct->pf_callback = pf_callback;
409     p_uct->p_data = p_data;
410
411     vlc_thread_create( p_uct, "check for update", update_CheckReal,
412                        VLC_THREAD_PRIORITY_LOW );
413 }
414
415 void* update_CheckReal( vlc_object_t* p_this )
416 {
417     update_check_thread_t *p_uct = (update_check_thread_t *)p_this;
418     bool b_ret;
419     int canc;
420
421     canc = vlc_savecancel ();
422     vlc_mutex_lock( &p_uct->p_update->lock );
423
424     EmptyRelease( p_uct->p_update );
425     b_ret = GetUpdateFile( p_uct->p_update );
426     vlc_mutex_unlock( &p_uct->p_update->lock );
427
428     if( p_uct->pf_callback )
429         (p_uct->pf_callback)( p_uct->p_data, b_ret );
430
431     vlc_restorecancel (canc);
432     return NULL;
433 }
434
435 /**
436  * Compare a given release's version number to the current VLC's one
437  *
438  * \param p_update structure
439  * \return true if we have to upgrade to the given version to be up to date
440  */
441 static bool is_strictly_greater( int * a, int * b, int n)
442 {
443     if( n <= 0 ) return false;
444     if(a[0] > b[0] ) return true;
445     if(a[0] == b[0] ) return is_strictly_greater( a+1, b+1, n-1 );
446     /* a[0] < b[0] */ return false;
447 }
448
449 bool update_NeedUpgrade( update_t *p_update )
450 {
451     assert( p_update );
452
453     int current_version[] = {
454         *PACKAGE_VERSION_MAJOR - '0',
455         *PACKAGE_VERSION_MINOR - '0',
456         *PACKAGE_VERSION_REVISION - '0',
457         *PACKAGE_VERSION_EXTRA
458     };
459     int latest_version[] = {
460         p_update->release.i_major,
461         p_update->release.i_minor,
462         p_update->release.i_revision,
463         p_update->release.extra
464     };
465
466     return is_strictly_greater( latest_version, current_version, 4 );
467 }
468
469 /**
470  * Convert a long int size in bytes to a string
471  *
472  * \param l_size the size in bytes
473  * \return the size as a string
474  */
475 static char *size_str( long int l_size )
476 {
477     char *psz_tmp = NULL;
478     int i_retval = 0;
479     if( l_size >> 30 )
480         i_retval = asprintf( &psz_tmp, _("%.1f GB"), (float)l_size/(1<<30) );
481     else if( l_size >> 20 )
482         i_retval = asprintf( &psz_tmp, _("%.1f MB"), (float)l_size/(1<<20) );
483     else if( l_size >> 10 )
484         i_retval = asprintf( &psz_tmp, _("%.1f kB"), (float)l_size/(1<<10) );
485     else
486         i_retval = asprintf( &psz_tmp, _("%ld B"), l_size );
487
488     return i_retval == -1 ? NULL : psz_tmp;
489 }
490
491 static void* update_DownloadReal( vlc_object_t *p_this );
492
493 /**
494  * Download the file given in the update_t
495  *
496  * \param p_update structure
497  * \param dir to store the download file
498  * \return nothing
499  */
500 void update_Download( update_t *p_update, const char *psz_destdir )
501 {
502     assert( p_update );
503
504     // If the object already exist, destroy it
505     if( p_update->p_download )
506     {
507         vlc_object_kill( p_update->p_download );
508         vlc_thread_join( p_update->p_download );
509         vlc_object_release( p_update->p_download );
510     }
511
512     update_download_thread_t *p_udt =
513         vlc_custom_create( p_update->p_libvlc, sizeof( *p_udt ),
514                            VLC_OBJECT_GENERIC, "update download" );
515     if( !p_udt )
516         return;
517
518     p_udt->p_update = p_update;
519     p_update->p_download = p_udt;
520     p_udt->psz_destdir = psz_destdir ? strdup( psz_destdir ) : NULL;
521
522     vlc_thread_create( p_udt, "download update", update_DownloadReal,
523                        VLC_THREAD_PRIORITY_LOW );
524 }
525
526 static void* update_DownloadReal( vlc_object_t *p_this )
527 {
528     update_download_thread_t *p_udt = (update_download_thread_t *)p_this;
529     dialog_progress_bar_t *p_progress = NULL;
530     long int l_size;
531     long int l_downloaded = 0;
532     float f_progress;
533     char *psz_status = NULL;
534     char *psz_downloaded = NULL;
535     char *psz_size = NULL;
536     char *psz_destfile = NULL;
537     char *psz_tmpdestfile = NULL;
538
539     FILE *p_file = NULL;
540     struct stat p_stat;
541     stream_t *p_stream = NULL;
542     void* p_buffer = NULL;
543     int i_read;
544     int canc;
545
546     update_t *p_update = p_udt->p_update;
547     char *psz_destdir = p_udt->psz_destdir;
548
549     msg_Dbg( p_udt, "Opening Stream '%s'", p_update->release.psz_url );
550     canc = vlc_savecancel ();
551
552     /* Open the stream */
553     p_stream = stream_UrlNew( p_udt, p_update->release.psz_url );
554     if( !p_stream )
555     {
556         msg_Err( p_udt, "Failed to open %s for reading", p_update->release.psz_url );
557         goto end;
558     }
559
560     /* Get the stream size */
561     l_size = stream_Size( p_stream );
562
563     /* Get the file name and open it*/
564     psz_tmpdestfile = strrchr( p_update->release.psz_url, '/' );
565     if( !psz_tmpdestfile )
566     {
567         msg_Err( p_udt, "The URL %s is badly formated",
568                  p_update->release.psz_url );
569         goto end;
570     }
571     psz_tmpdestfile++;
572
573     if( utf8_stat( psz_destdir, &p_stat) == 0 && (p_stat.st_mode & S_IFDIR) )
574     {
575         if( asprintf( &psz_destfile, "%s%c%s", psz_destdir, DIR_SEP_CHAR, psz_tmpdestfile ) == -1 )
576             goto end;
577     }
578     else if( psz_destdir )
579         psz_destfile = strdup( psz_destdir );
580     else
581         psz_destfile = strdup( psz_tmpdestfile );
582
583     p_file = utf8_fopen( psz_destfile, "w" );
584     if( !p_file )
585     {
586         msg_Err( p_udt, "Failed to open %s for writing", psz_destfile );
587         dialog_FatalWait( p_udt, _("Saving file failed"),
588             _("Failed to open \"%s\" for writing"),
589              psz_destfile );
590         goto end;
591     }
592
593     /* Create a buffer and fill it with the downloaded file */
594     p_buffer = (void *)malloc( 1 << 10 );
595     if( !p_buffer )
596     {
597         msg_Err( p_udt, "Can't malloc (1 << 10) bytes! download cancelled." );
598         goto end;
599     }
600
601     msg_Dbg( p_udt, "Downloading Stream '%s'", p_update->release.psz_url );
602
603     psz_size = size_str( l_size );
604     if( asprintf( &psz_status, _("%s\nDownloading... %s/%s %.1f%% done"),
605         p_update->release.psz_url, "0.0", psz_size, 0.0 ) != -1 )
606     {
607         p_progress = dialog_ProgressCreate( p_udt, _( "Downloading ..."),
608                                             psz_status, _("Cancel") );
609         free( psz_status );
610     }
611
612     while( vlc_object_alive( p_udt ) &&
613            ( i_read = stream_Read( p_stream, p_buffer, 1 << 10 ) ) &&
614            !dialog_ProgressCancelled( p_progress ) )
615     {
616         if( fwrite( p_buffer, i_read, 1, p_file ) < 1 )
617         {
618             msg_Err( p_udt, "Failed to write into %s", psz_destfile );
619             break;
620         }
621
622         l_downloaded += i_read;
623         psz_downloaded = size_str( l_downloaded );
624         f_progress = (float)l_downloaded/(float)l_size;
625
626         if( asprintf( &psz_status, _( "%s\nDownloading... %s/%s %.1f%% done" ),
627                       p_update->release.psz_url, psz_downloaded, psz_size,
628                       f_progress ) != -1 )
629         {
630             dialog_ProgressSet( p_progress, psz_status, f_progress );
631             free( psz_status );
632         }
633         free( psz_downloaded );
634     }
635
636     /* Finish the progress bar or delete the file if the user had canceled */
637     fclose( p_file );
638     p_file = NULL;
639
640     if( vlc_object_alive( p_udt ) &&
641         !dialog_ProgressCancelled( p_progress ) )
642     {
643         if( asprintf( &psz_status, _("%s\nDone %s (100.0%%)"),
644             p_update->release.psz_url, psz_size ) != -1 )
645         {
646             dialog_ProgressDestroy( p_progress );
647             p_progress = NULL;
648             free( psz_status );
649         }
650     }
651     else
652     {
653         utf8_unlink( psz_destfile );
654         goto end;
655     }
656
657     signature_packet_t sign;
658     if( download_signature( VLC_OBJECT( p_udt ), &sign,
659             p_update->release.psz_url ) != VLC_SUCCESS )
660     {
661         utf8_unlink( psz_destfile );
662
663         dialog_FatalWait( p_udt, _("File could not be verified"),
664             _("It was not possible to download a cryptographic signature for "
665               "the downloaded file \"%s\". Thus, it was deleted."),
666             psz_destfile );
667         msg_Err( p_udt, "Couldn't download signature of downloaded file" );
668         goto end;
669     }
670
671     if( memcmp( sign.issuer_longid, p_update->p_pkey->longid, 8 ) )
672     {
673         utf8_unlink( psz_destfile );
674         msg_Err( p_udt, "Invalid signature issuer" );
675         dialog_FatalWait( p_udt, _("Invalid signature"),
676             _("The cryptographic signature for the downloaded file \"%s\" was "
677               "invalid and could not be used to securely verify it. Thus, the "
678               "file was deleted."),
679             psz_destfile );
680         goto end;
681     }
682
683     if( sign.type != BINARY_SIGNATURE )
684     {
685         utf8_unlink( psz_destfile );
686         msg_Err( p_udt, "Invalid signature type" );
687         dialog_FatalWait( p_udt, _("Invalid signature"),
688             _("The cryptographic signature for the downloaded file \"%s\" was "
689               "invalid and could not be used to securely verify it. Thus, the "
690               "file was deleted."),
691             psz_destfile );
692         goto end;
693     }
694
695     uint8_t *p_hash = hash_sha1_from_file( psz_destfile, &sign );
696     if( !p_hash )
697     {
698         msg_Err( p_udt, "Unable to hash %s", psz_destfile );
699         utf8_unlink( psz_destfile );
700         dialog_FatalWait( p_udt, _("File not verifiable"),
701             _("It was not possible to securely verify the downloaded file"
702               " \"%s\". Thus, it was deleted."),
703             psz_destfile );
704
705         goto end;
706     }
707
708     if( p_hash[0] != sign.hash_verification[0] ||
709         p_hash[1] != sign.hash_verification[1] )
710     {
711         utf8_unlink( psz_destfile );
712         dialog_FatalWait( p_udt, _("File corrupted"),
713             _("Downloaded file \"%s\" was corrupted. Thus, it was deleted."),
714              psz_destfile );
715         msg_Err( p_udt, "Bad SHA1 hash for %s", psz_destfile );
716         free( p_hash );
717         goto end;
718     }
719
720     if( verify_signature( sign.r, sign.s, &p_update->p_pkey->key, p_hash )
721             != VLC_SUCCESS )
722     {
723         utf8_unlink( psz_destfile );
724         dialog_FatalWait( p_udt, _("File corrupted"),
725             _("Downloaded file \"%s\" was corrupted. Thus, it was deleted."),
726              psz_destfile );
727         msg_Err( p_udt, "BAD SIGNATURE for %s", psz_destfile );
728         free( p_hash );
729         goto end;
730     }
731
732     msg_Info( p_udt, "%s authenticated", psz_destfile );
733     free( p_hash );
734
735 end:
736     if( p_progress )
737         dialog_ProgressDestroy( p_progress );
738     if( p_stream )
739         stream_Delete( p_stream );
740     if( p_file )
741         fclose( p_file );
742     free( psz_destdir );
743     free( psz_destfile );
744     free( p_buffer );
745     free( psz_size );
746
747     p_udt->p_update->p_download = NULL;
748
749     vlc_restorecancel( canc );
750     return NULL;
751 }
752
753 update_release_t *update_GetRelease( update_t *p_update )
754 {
755     return &p_update->release;
756 }
757
758 #else
759 update_t *__update_New( vlc_object_t *p_this )
760 {
761     (void)p_this;
762     return NULL;
763 }
764
765 void update_Delete( update_t *p_update )
766 {
767     (void)p_update;
768 }
769
770 void update_Check( update_t *p_update, void (*pf_callback)( void*, bool ),
771                    void *p_data )
772 {
773     (void)p_update; (void)pf_callback; (void)p_data;
774 }
775
776 bool update_NeedUpgrade( update_t *p_update )
777 {
778     (void)p_update;
779     return false;
780 }
781
782 void update_Download( update_t *p_update, const char *psz_destdir )
783 {
784     (void)p_update; (void)psz_destdir;
785 }
786
787 update_release_t *update_GetRelease( update_t *p_update )
788 {
789     (void)p_update;
790     return NULL;
791 }
792 #endif