1 /*****************************************************************************
2 * update.c: VLC update and plugins download
3 *****************************************************************************
4 * Copyright (C) 2005 the VideoLAN team
7 * Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
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 release 2 of the License, or
12 * (at your option) any later release.
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.
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, USA.
22 *****************************************************************************/
25 * --> check release types.
26 * --> make sure that the version comparision method is ok.
31 * This file contains functions related to VLC and plugins update management
34 /*****************************************************************************
36 *****************************************************************************/
37 #include <stdlib.h> /* malloc(), free() */
38 #include <ctype.h> /* tolower() */
42 #include "vlc_update.h"
44 #include "vlc_block.h"
45 #include "vlc_stream.h"
47 #include "vlc_interaction.h"
49 /*****************************************************************************
51 *****************************************************************************/
53 /* All release notes and source packages should match on "*"
54 * Only binary installers are OS specific ( we only provide these
55 * for Win32, Mac OS X, WincCE, beos(?) ) */
56 #if defined( UNDER_CE )
57 # define UPDATE_VLC_OS "*"
58 # define UPDATE_VLC_ARCH "*"
59 #elif defined( WIN32 )
60 # define UPDATE_VLC_OS "windows"
61 # define UPDATE_VLC_ARCH "i386"
62 #elif defined( __APPLE__ )
63 # define UPDATE_VLC_OS "macosx"
64 # if defined( __powerpc__ ) || defined( __ppc__ ) || defined( __ppc64__ )
65 # define UPDATE_VLC_ARCH "ppc"
67 # define UPDATE_VLC_ARCH "x86"
69 #elif defined( SYS_BEOS )
70 # define UPDATE_VLC_OS "beos"
71 # define UPDATE_VLC_ARCH "i386"
73 # define UPDATE_VLC_OS "*"
74 # define UPDATE_VLC_ARCH "*"
77 #define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status.xml"
78 #define UPDATE_VLC_MIRRORS_URL "http://update.videolan.org/mirrors.xml"
80 #define FREE( a ) free(a);a=NULL;
81 #define STRDUP( a ) ( a ? strdup( a ) : NULL )
83 /*****************************************************************************
85 *****************************************************************************/
87 void FreeMirrorsList( update_t * );
88 void FreeReleasesList( update_t * );
89 void GetMirrorsList( update_t *, vlc_bool_t );
90 void GetFilesList( update_t *, vlc_bool_t );
92 int CompareReleases( struct update_release_t *, struct update_release_t * );
93 int CompareReleaseToCurrent( struct update_release_t * );
95 unsigned int update_iterator_Reset( update_iterator_t * );
96 unsigned int update_iterator_NextFile( update_iterator_t * );
97 unsigned int update_iterator_PrevFile( update_iterator_t * );
98 unsigned int update_iterator_NextMirror( update_iterator_t * );
99 unsigned int update_iterator_PrevMirror( update_iterator_t * );
101 void update_iterator_GetData( update_iterator_t * );
102 void update_iterator_ClearData( update_iterator_t * );
104 /*****************************************************************************
106 *****************************************************************************/
109 * Create a new update VLC struct
111 * \param p_this the calling vlc_object
112 * \return pointer to new update_t or NULL
114 update_t *__update_New( vlc_object_t *p_this )
118 if( p_this == NULL ) return NULL;
120 p_update = (update_t *)malloc( sizeof( update_t ) );
122 vlc_mutex_init( p_this, &p_update->lock );
124 p_update->p_vlc = p_this->p_vlc;
126 p_update->p_releases = NULL;
127 p_update->i_releases = 0;
128 p_update->b_releases = VLC_FALSE;
130 p_update->p_mirrors = NULL;
131 p_update->i_mirrors = 0;
132 p_update->b_mirrors = VLC_FALSE;
138 * Delete an update_t struct
140 * \param p_update update_t* pointer
143 void update_Delete( update_t *p_update )
145 vlc_mutex_destroy( &p_update->lock );
146 FreeMirrorsList( p_update );
147 FreeReleasesList( p_update );
152 * Empty the mirrors list
153 * *p_update should be locked before using this function
155 * \param p_update pointer to the update struct
158 void FreeMirrorsList( update_t *p_update )
162 for( i = 0; i < p_update->i_mirrors; i++ )
164 free( p_update->p_mirrors[i].psz_name );
165 free( p_update->p_mirrors[i].psz_location );
166 free( p_update->p_mirrors[i].psz_type );
167 free( p_update->p_mirrors[i].psz_base_url );
169 FREE( p_update->p_mirrors );
170 p_update->i_mirrors = 0;
171 p_update->b_mirrors = VLC_FALSE;
175 * Empty the releases list
176 * *p_update should be locked before calling this function
178 * \param p_update pointer to the update struct
181 void FreeReleasesList( update_t *p_update )
185 for( i = 0; i < p_update->i_releases; i++ )
188 struct update_release_t *p_release = (p_update->p_releases + i);
189 for( j = 0; j < p_release->i_files; j++ )
191 free( p_release->p_files[j].psz_md5 );
192 free( p_release->p_files[j].psz_url );
193 free( p_release->p_files[j].psz_description );
195 free( p_release->psz_major );
196 free( p_release->psz_minor );
197 free( p_release->psz_revision );
198 free( p_release->psz_extra );
199 free( p_release->psz_svn_revision );
200 free( p_release->p_files );
202 FREE( p_update->p_releases );
203 p_update->i_releases = 0;
204 p_update->b_releases = VLC_FALSE;
208 * Get the mirrors list XML file and parse it
209 * *p_update has to be unlocked when calling this function
211 * \param p_update pointer to the update struct
212 * \param b_force set to VLC_TRUE if you want to force the mirrors list update
215 void GetMirrorsList( update_t *p_update, vlc_bool_t b_force )
217 stream_t *p_stream = NULL;
220 xml_reader_t *p_xml_reader = NULL;
222 char *psz_eltname = NULL;
223 //char *psz_eltvalue = NULL;
224 char *psz_name = NULL;
225 char *psz_value = NULL;
227 struct update_mirror_t tmp_mirror = {0};
229 vlc_mutex_lock( &p_update->lock );
231 if( p_update->b_mirrors && b_force == VLC_FALSE )
233 vlc_mutex_unlock( &p_update->lock );
237 p_xml = xml_Create( p_update->p_vlc );
240 msg_Err( p_update->p_vlc, "Failed to open XML parser" );
244 p_stream = stream_UrlNew( p_update->p_vlc, UPDATE_VLC_MIRRORS_URL );
247 msg_Err( p_update->p_vlc, "Failed to open %s for reading",
248 UPDATE_VLC_MIRRORS_URL );
252 p_xml_reader = xml_ReaderCreate( p_xml, p_stream );
256 msg_Err( p_update->p_vlc, "Failed to open %s for parsing",
257 UPDATE_VLC_MIRRORS_URL );
261 if( p_update->p_mirrors )
263 FreeMirrorsList( p_update );
266 while( xml_ReaderRead( p_xml_reader ) == 1 )
268 switch( xml_ReaderNodeType( p_xml_reader ) )
271 msg_Err( p_update->p_vlc, "Error while parsing %s",
272 UPDATE_VLC_MIRRORS_URL );
275 case XML_READER_STARTELEM:
276 psz_eltname = xml_ReaderName( p_xml_reader );
279 msg_Err( p_update->p_vlc, "Error while parsing %s",
280 UPDATE_VLC_MIRRORS_URL );
284 while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
286 psz_name = xml_ReaderName( p_xml_reader );
287 psz_value = xml_ReaderValue( p_xml_reader );
289 if( !psz_name || !psz_value )
291 msg_Err( p_update->p_vlc, "Error while parsing %s",
292 UPDATE_VLC_MIRRORS_URL );
296 if( !strcmp( psz_eltname, "mirror" ) )
298 if( !strcmp( psz_name, "name" ) )
299 tmp_mirror.psz_name = STRDUP( psz_value );
300 else if( !strcmp( psz_name, "location" ) )
301 tmp_mirror.psz_location = STRDUP( psz_value );
303 else if( !strcmp( psz_eltname, "url" ) )
305 if( !strcmp( psz_name, "type" ) )
306 tmp_mirror.psz_type = STRDUP( psz_value );
307 else if( !strcmp( psz_name, "base" ) )
308 tmp_mirror.psz_base_url = STRDUP( psz_value );
313 if( !strcmp( psz_eltname, "url" ) )
315 /* append to mirrors list */
316 p_update->p_mirrors =
317 (struct update_mirror_t *)realloc( p_update->p_mirrors,
318 (++(p_update->i_mirrors))
319 *sizeof( struct update_mirror_t ) );
320 p_update->p_mirrors[ p_update->i_mirrors - 1 ] =
322 tmp_mirror.psz_name = STRDUP( tmp_mirror.psz_name );
323 tmp_mirror.psz_location = STRDUP( tmp_mirror.psz_location );
324 tmp_mirror.psz_type = NULL;
325 tmp_mirror.psz_base_url = NULL;
330 case XML_READER_ENDELEM:
331 psz_eltname = xml_ReaderName( p_xml_reader );
334 msg_Err( p_update->p_vlc, "Error while parsing %s",
335 UPDATE_VLC_MIRRORS_URL );
339 if( !strcmp( psz_eltname, "mirror" ) )
341 FREE( tmp_mirror.psz_name );
342 FREE( tmp_mirror.psz_location );
348 /*case XML_READER_TEXT:
349 psz_eltvalue = xml_ReaderValue( p_xml_reader );
350 FREE( psz_eltvalue );
355 p_update->b_mirrors = VLC_TRUE;
358 vlc_mutex_unlock( &p_update->lock );
361 //free( psz_eltvalue );
365 free( tmp_mirror.psz_name );
366 free( tmp_mirror.psz_location );
367 free( tmp_mirror.psz_type );
368 free( tmp_mirror.psz_base_url );
370 if( p_xml_reader && p_xml )
371 xml_ReaderDelete( p_xml, p_xml_reader );
373 stream_Delete( p_stream );
379 * Get the files list XML file and parse it
380 * *p_update has to be unlocked when calling this function
382 * \param p_update pointer to update struct
383 * \param b_force set to VLC_TRUE if you want to force the files list update
386 void GetFilesList( update_t *p_update, vlc_bool_t b_force )
388 stream_t *p_stream = NULL;
391 xml_reader_t *p_xml_reader = NULL;
393 char *psz_eltname = NULL;
394 char *psz_eltvalue = NULL;
395 char *psz_name = NULL;
396 char *psz_value = NULL;
398 struct update_release_t *p_release = NULL;
399 struct update_release_t tmp_release = {0};
400 struct update_file_t tmp_file = {0};
402 vlc_bool_t b_os = VLC_FALSE, b_arch = VLC_FALSE;
404 tmp_release.i_type = UPDATE_RELEASE_TYPE_STABLE;
406 vlc_mutex_lock( &p_update->lock );
408 if( p_update->b_releases && b_force == VLC_FALSE )
410 vlc_mutex_unlock( &p_update->lock );
414 p_xml = xml_Create( p_update->p_vlc );
417 msg_Err( p_update->p_vlc, "Failed to open XML parser" );
421 p_stream = stream_UrlNew( p_update->p_vlc, UPDATE_VLC_STATUS_URL );
424 msg_Err( p_update->p_vlc, "Failed to open %s for reading",
425 UPDATE_VLC_STATUS_URL );
429 p_xml_reader = xml_ReaderCreate( p_xml, p_stream );
433 msg_Err( p_update->p_vlc, "Failed to open %s for parsing",
434 UPDATE_VLC_STATUS_URL );
438 if( p_update->p_releases )
440 FreeReleasesList( p_update );
443 while( xml_ReaderRead( p_xml_reader ) == 1 )
445 switch( xml_ReaderNodeType( p_xml_reader ) )
448 msg_Err( p_update->p_vlc, "Error while parsing %s",
449 UPDATE_VLC_STATUS_URL );
452 case XML_READER_STARTELEM:
453 psz_eltname = xml_ReaderName( p_xml_reader );
456 msg_Err( p_update->p_vlc, "Error while parsing %s",
457 UPDATE_VLC_STATUS_URL );
461 while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
463 psz_name = xml_ReaderName( p_xml_reader );
464 psz_value = xml_ReaderValue( p_xml_reader );
466 if( !psz_name || !psz_value )
468 msg_Err( p_update->p_vlc, "Error while parsing %s",
469 UPDATE_VLC_STATUS_URL );
475 if( strcmp( psz_eltname, "version" ) == 0 )
477 if( !strcmp( psz_name, "major" ) )
478 tmp_release.psz_major = STRDUP( psz_value );
479 else if( !strcmp( psz_name, "minor" ) )
480 tmp_release.psz_minor = STRDUP( psz_value );
481 else if( !strcmp( psz_name, "revision" ) )
482 tmp_release.psz_revision = STRDUP( psz_value );
483 else if( !strcmp( psz_name, "extra" ) )
484 tmp_release.psz_extra = STRDUP( psz_value );
485 else if( !strcmp( psz_name, "svn" ) )
486 tmp_release.psz_svn_revision =
488 else if( !strcmp( psz_name, "version" ) )
490 if( !strcmp( psz_value, "unstable" ) )
492 UPDATE_RELEASE_TYPE_UNSTABLE;
493 else if( !strcmp( psz_value, "testing" ) )
495 UPDATE_RELEASE_TYPE_TESTING;
498 UPDATE_RELEASE_TYPE_STABLE;
501 else if( !strcmp( psz_eltname, "file" ) )
503 if( !strcmp( psz_name, "type" ) )
505 if( !strcmp( psz_value, "info" ) )
506 tmp_file.i_type = UPDATE_FILE_TYPE_INFO;
507 else if( !strcmp( psz_value, "source" ) )
508 tmp_file.i_type = UPDATE_FILE_TYPE_SOURCE;
509 else if( !strcmp( psz_value, "binary" ) )
510 tmp_file.i_type = UPDATE_FILE_TYPE_BINARY;
511 else if( !strcmp( psz_value, "plugin" ) )
512 tmp_file.i_type = UPDATE_FILE_TYPE_PLUGIN;
514 tmp_file.i_type = UPDATE_FILE_TYPE_UNDEF;
516 else if( !strcmp( psz_name, "md5" ) )
517 tmp_file.psz_md5 = STRDUP( psz_value );
518 else if( !strcmp( psz_name, "size" ) )
519 tmp_file.l_size = atol( psz_value );
520 else if( !strcmp( psz_name, "url" ) )
521 tmp_file.psz_url = STRDUP( psz_value );
524 if( !strcmp( psz_name, "name" )
525 && ( !strcmp( psz_value, UPDATE_VLC_OS )
526 || !strcmp( psz_value, "*" ) )
527 && !strcmp( psz_eltname, "os" ) )
531 if( b_os && !strcmp( psz_name, "name" )
532 && ( !strcmp( psz_value, UPDATE_VLC_ARCH )
533 || !strcmp( psz_value, "*" ) )
534 && !strcmp( psz_eltname, "arch" ) )
541 if( ( b_os && b_arch && strcmp( psz_eltname, "arch" ) ) )
543 if( !strcmp( psz_eltname, "version" ) )
546 /* look for a previous occurence of this release */
547 for( i = 0; i < p_update->i_releases; i++ )
549 p_release = p_update->p_releases + i;
550 if( CompareReleases( p_release, &tmp_release )
551 == UPDATE_RELEASE_STATUS_EQUAL )
556 /* if this is the first time that we see this release,
557 * append it to the list of releases */
558 if( i == p_update->i_releases )
560 tmp_release.i_status =
561 CompareReleaseToCurrent( &tmp_release );
562 p_update->p_releases =
563 (struct update_release_t *)realloc( p_update->p_releases,
564 (++(p_update->i_releases))*sizeof( struct update_release_t ) );
565 p_update->p_releases[ p_update->i_releases - 1 ] =
568 p_update->p_releases + p_update->i_releases - 1;
569 tmp_release.psz_major = NULL;
570 tmp_release.psz_minor = NULL;
571 tmp_release.psz_revision = NULL;
572 tmp_release.psz_extra = NULL;
573 tmp_release.psz_svn_revision = NULL;
574 tmp_release.i_type = UPDATE_RELEASE_TYPE_STABLE;
575 tmp_release.i_status = 0;
576 tmp_release.p_files = NULL;
577 tmp_release.i_files = 0;
581 FREE( tmp_release.psz_major );
582 FREE( tmp_release.psz_minor );
583 FREE( tmp_release.psz_revision );
584 FREE( tmp_release.psz_extra );
585 FREE( tmp_release.psz_svn_revision );
586 tmp_release.i_type = UPDATE_RELEASE_TYPE_STABLE;
587 FREE( tmp_release.p_files );
588 tmp_release.i_files = 0;
591 else if( !strcmp( psz_eltname, "file" ) )
593 /* append file to p_release's file list */
594 if( p_release == NULL )
599 (struct update_file_t *)realloc( p_release->p_files,
600 (++(p_release->i_files))*sizeof( struct update_file_t ) );
601 p_release->p_files[ p_release->i_files - 1 ] = tmp_file;
602 tmp_file.i_type = UPDATE_FILE_TYPE_UNDEF;
603 tmp_file.psz_md5 = NULL;
605 tmp_file.psz_url = NULL;
606 tmp_file.psz_description = NULL;
612 case XML_READER_ENDELEM:
613 psz_eltname = xml_ReaderName( p_xml_reader );
616 msg_Err( p_update->p_vlc, "Error while parsing %s",
617 UPDATE_VLC_STATUS_URL );
621 if( !strcmp( psz_eltname, "os" ) )
623 else if( !strcmp( psz_eltname, "arch" ) )
628 case XML_READER_TEXT:
629 psz_eltvalue = xml_ReaderValue( p_xml_reader );
630 if( p_release && p_release->i_files )
631 p_release->p_files[ p_release->i_files - 1 ]
632 .psz_description = STRDUP( psz_eltvalue );
633 FREE( psz_eltvalue );
638 p_update->b_releases = VLC_TRUE;
641 vlc_mutex_unlock( &p_update->lock );
644 free( psz_eltvalue );
648 free( tmp_release.psz_major );
649 free( tmp_release.psz_minor );
650 free( tmp_release.psz_revision );
651 free( tmp_release.psz_extra );
652 free( tmp_release.psz_svn_revision );
654 free( tmp_file.psz_md5 );
655 free( tmp_file.psz_url );
656 free( tmp_file.psz_description );
658 if( p_xml_reader && p_xml )
659 xml_ReaderDelete( p_xml, p_xml_reader );
661 stream_Delete( p_stream );
669 * \param p_update pointer to update struct
670 * \param b_force set to VLC_TRUE if you want to force the update
673 void update_Check( update_t *p_update, vlc_bool_t b_force )
675 if( p_update == NULL ) return;
676 GetMirrorsList( p_update, b_force );
677 GetFilesList( p_update, b_force );
681 * Compare two release numbers
682 * The comparision algorith basically performs an alphabetical order (strcmp)
683 * comparision of each of the version number elements until it finds two
684 * different ones. This is the tricky function.
686 * \param p1 first release
687 * \param p2 second release
688 * \return like strcmp
690 int CompareReleases( struct update_release_t *p1, struct update_release_t *p2 )
693 if( ( d = strcmp( p1->psz_major, p2->psz_major ) ) ) ;
694 else if( ( d = strcmp( p1->psz_minor, p2->psz_minor ) ) ) ;
695 else if( ( d = strcmp( p1->psz_revision, p2->psz_revision ) ) ) ;
698 d = strcmp( p1->psz_extra, p2->psz_extra );
702 * not num < NULL < num
703 * -test and -svn releases are thus always considered older than
704 * -'' or -0 releases, which is the best i could come up with */
707 strtol( p1->psz_extra, &psz_end1, 10 );
708 strtol( p2->psz_extra, &psz_end2, 10 );
709 if( psz_end2 == p2->psz_extra
710 && ( psz_end1 != p1->psz_extra || *p1->psz_extra == '\0' ) )
715 return UPDATE_RELEASE_STATUS_OLDER;
717 return UPDATE_RELEASE_STATUS_EQUAL;
719 return UPDATE_RELEASE_STATUS_NEWER;
723 * Compare a given release's version number to the current VLC's one
726 * \return >0 if newer, 0 if equal and <0 if older
728 int CompareReleaseToCurrent( struct update_release_t *p )
730 struct update_release_t c = {0};
732 c.psz_major = STRDUP( PACKAGE_VERSION_MAJOR );
733 c.psz_minor = STRDUP( PACKAGE_VERSION_MINOR );
734 c.psz_revision = STRDUP( PACKAGE_VERSION_REVISION );
735 c.psz_extra = STRDUP( PACKAGE_VERSION_EXTRA );
736 r = CompareReleases( p, &c );
739 free( c.psz_revision );
744 /*****************************************************************************
745 * Updatei_iterator_t functions
746 *****************************************************************************/
749 * Create a new update iterator structure. This structure can then be used to
750 * describe a position and move through the update and mirror trees/lists.
751 * This will use an existing update struct or create a new one if none is
754 * \param p_u the calling update_t
755 * \return a pointer to an update iterator
757 update_iterator_t *update_iterator_New( update_t *p_u )
759 update_iterator_t *p_uit = NULL;
764 p_uit = (update_iterator_t *)malloc( sizeof( update_iterator_t ) );
765 if( p_uit == NULL ) return NULL;
773 p_uit->i_t = UPDATE_FILE_TYPE_ALL;
774 p_uit->i_rs = UPDATE_RELEASE_STATUS_ALL;
775 p_uit->i_rt = UPDATE_RELEASE_TYPE_STABLE;
777 p_uit->file.i_type = UPDATE_FILE_TYPE_NONE;
778 p_uit->file.psz_md5 = NULL;
779 p_uit->file.psz_url = NULL;
780 p_uit->file.l_size = 0;
781 p_uit->file.psz_description = NULL;
783 p_uit->release.psz_version = NULL;
784 p_uit->release.psz_svn_revision = NULL;
785 p_uit->release.i_type = UPDATE_RELEASE_TYPE_UNSTABLE;
786 p_uit->release.i_status = UPDATE_RELEASE_STATUS_NONE;
788 p_uit->mirror.psz_name = NULL;
789 p_uit->mirror.psz_location = NULL;
790 p_uit->mirror.psz_type = NULL;
796 * Delete an update iterator structure (duh!)
798 * \param p_uit pointer to an update iterator
801 void update_iterator_Delete( update_iterator_t *p_uit )
804 update_iterator_ClearData( p_uit );
809 * Reset an update_iterator_t structure
811 * \param p_uit pointer to an update iterator
812 * \return UPDATE_FAIL upon error, UPDATE_SUCCESS otherwise
814 unsigned int update_iterator_Reset( update_iterator_t *p_uit )
816 if( !p_uit ) return UPDATE_FAIL;
822 update_iterator_ClearData( p_uit );
823 return UPDATE_SUCCESS;
827 * Finds the next file in the update tree that matches status and type
828 * requirements set in the update_iterator
830 * \param p_uit update iterator
831 * \return UPDATE_FAIL if we can't find the next file, UPDATE_SUCCESS|UPDATE_FILE if we stay in the same release, UPDATE_SUCCESS|UPDATE_RELEASE|UPDATE_FILE if we change the release index
833 unsigned int update_iterator_NextFile( update_iterator_t *p_uit )
837 if( !p_uit ) return UPDATE_FAIL;
841 /* if the update iterator was already in a "no match" state, start over */
842 if( p_uit->i_r == -1 ) p_uit->i_r = 0;
843 //if( p_uit->i_f == -1 ) p_uit->i_f = 0;
845 vlc_mutex_lock( &p_uit->p_u->lock );
847 for( r = p_uit->i_r; r < p_uit->p_u->i_releases; r++ )
849 if( !( p_uit->p_u->p_releases[r].i_status & p_uit->i_rs ) ) continue;
850 for( f = ( r == p_uit->i_r ? p_uit->i_f + 1 : 0 );
851 f < p_uit->p_u->p_releases[r].i_files; f++ )
853 if( p_uit->p_u->p_releases[r].p_files[f].i_type & p_uit->i_t )
855 goto done;/* "double break" */
863 r = p_uit->p_u->i_releases;
865 if( old_r == p_uit->i_r )
867 update_iterator_GetData( p_uit );
868 vlc_mutex_unlock( &p_uit->p_u->lock );
869 return UPDATE_SUCCESS|UPDATE_FILE;
871 else if( p_uit->i_r == r )
875 update_iterator_GetData( p_uit );
876 vlc_mutex_unlock( &p_uit->p_u->lock );
881 update_iterator_GetData( p_uit );
882 vlc_mutex_unlock( &p_uit->p_u->lock );
883 return UPDATE_SUCCESS|UPDATE_RELEASE|UPDATE_FILE;
888 * Finds the previous file in the update tree that matches status and type
889 * requirements set in the update_iterator
891 * \param p_uit update iterator
892 * \return UPDATE_FAIL if we can't find the previous file, UPDATE_SUCCESS|UPDATE_FILE if we stay in the same release, UPDATE_SUCCESS|UPDATE_RELEASE|UPDATE_FILE if we change the release index
895 unsigned int update_iterator_PrevFile( update_iterator_t *p_uit )
899 if( !p_uit ) return UPDATE_FAIL;
903 /* if the update iterator was already in a "no match" state, start over
904 * (begin at the end of the list) */
905 if( p_uit->i_r == -1 ) p_uit->i_r = p_uit->p_u->i_releases - 1;
906 p_uit->i_f = p_uit->p_u->p_releases[p_uit->i_r].i_files + 1;
908 vlc_mutex_lock( &p_uit->p_u->lock );
910 for( r = p_uit->i_r; r >= 0; r-- )
912 if( !( p_uit->p_u->p_releases[r].i_status & p_uit->i_rs ) ) continue;
913 for( f =( r==p_uit->i_r ? p_uit->i_f - 1 : p_uit->p_u->p_releases[r].i_files );
916 if( p_uit->p_u->p_releases[r].p_files[f].i_type & p_uit->i_t )
918 goto done;/* "double break" */
926 r = p_uit->p_u->i_releases;
928 if( old_r == p_uit->i_r )
930 update_iterator_GetData( p_uit );
931 vlc_mutex_unlock( &p_uit->p_u->lock );
932 return UPDATE_SUCCESS|UPDATE_FILE;
934 else if( p_uit->i_r == -1 )
938 update_iterator_GetData( p_uit );
939 vlc_mutex_unlock( &p_uit->p_u->lock );
944 update_iterator_GetData( p_uit );
945 vlc_mutex_unlock( &p_uit->p_u->lock );
946 return UPDATE_SUCCESS|UPDATE_RELEASE|UPDATE_FILE;
951 * Finds the next mirror in the update tree
953 * \param update iterator
954 * \return UPDATE_FAIL if we can't find the next mirror, UPDATE_SUCCESS|UPDATE_MIRROR otherwise
956 unsigned int update_iterator_NextMirror( update_iterator_t *p_uit )
958 if( !p_uit ) return UPDATE_FAIL;
959 vlc_mutex_lock( &p_uit->p_u->lock );
961 if( p_uit->i_m >= p_uit->p_u->i_mirrors ) p_uit->i_m = -1;
962 update_iterator_GetData( p_uit );
963 vlc_mutex_unlock( &p_uit->p_u->lock );
964 return p_uit->i_m == -1 ? UPDATE_FAIL : UPDATE_SUCCESS|UPDATE_MIRROR;
968 * Finds the previous mirror in the update tree
970 * \param update iterator
971 * \return UPDATE_FAIL if we can't find a previous mirror, UPDATE_SUCCESS|UPDATE_MIRROR otherwise
973 unsigned int update_iterator_PrevMirror( update_iterator_t *p_uit )
975 if( !p_uit ) return UPDATE_FAIL;
976 vlc_mutex_lock( &p_uit->p_u->lock );
978 update_iterator_GetData( p_uit );
979 vlc_mutex_unlock( &p_uit->p_u->lock );
980 return p_uit->i_m == -1 ? UPDATE_FAIL : UPDATE_SUCCESS|UPDATE_MIRROR;
984 * Change the update iterator's position in the file and mirrors tree
985 * If position is negative, don't change it
987 * \param i_m position in mirrors list
988 * \param i_r position in releases list
989 * \param i_f position in release's files list
990 * \return UPDATE_FAIL when changing position fails or position wasn't changed, a combination of UPDATE_MIRROR, UPDATE_RELEASE and UPDATE_FILE otherwise
992 unsigned int update_iterator_ChooseMirrorAndFile( update_iterator_t *p_uit,
993 int i_m, int i_r, int i_f )
995 unsigned int i_val = 0;
997 if( !p_uit ) return 0;
998 vlc_mutex_lock( &p_uit->p_u->lock );
1002 if( i_m < p_uit->p_u->i_mirrors )
1004 if( i_m != p_uit->i_m )
1005 i_val |= UPDATE_MIRROR;
1013 if( i_r < p_uit->p_u->i_releases )
1015 if( i_r != p_uit->i_r )
1016 i_val |= UPDATE_FILE;
1024 if( i_r >= 0 && i_r < p_uit->p_u->i_releases
1025 && i_f < p_uit->p_u->p_releases[p_uit->i_r].i_files )
1027 if( i_f != p_uit->i_f )
1028 i_val |= UPDATE_FILE;
1034 update_iterator_GetData( p_uit );
1035 vlc_mutex_unlock( &p_uit->p_u->lock );
1037 if( ( i_m < 0 || p_uit->i_m >= 0 )
1038 && ( i_r < 0 || p_uit->i_r >= 0 )
1039 && ( i_f < 0 || p_uit->i_f >= 0 ) )
1041 /* Everything worked */
1042 return UPDATE_SUCCESS|i_val;
1046 /* Something failed */
1052 * Fills the iterator data (file, release and mirror structs)
1053 * The update struct should be locked before calling this function.
1055 * \param p_uit update iterator
1058 void update_iterator_GetData( update_iterator_t *p_uit )
1060 struct update_release_t *p_r = NULL;
1061 struct update_file_t *p_f = NULL;
1062 struct update_mirror_t *p_m = NULL;
1064 update_iterator_ClearData( p_uit );
1066 if( p_uit->i_m >= 0 )
1068 p_m = p_uit->p_u->p_mirrors + p_uit->i_m;
1069 p_uit->mirror.psz_name = STRDUP( p_m->psz_name );
1070 p_uit->mirror.psz_location = STRDUP( p_m->psz_location );
1071 p_uit->mirror.psz_type = STRDUP( p_m->psz_type );
1074 if( p_uit->i_r >= 0 )
1076 p_r = p_uit->p_u->p_releases + p_uit->i_r;
1077 asprintf( &p_uit->release.psz_version, "%s.%s.%s-%s",
1082 p_uit->release.psz_svn_revision = STRDUP( p_r->psz_svn_revision );
1083 p_uit->release.i_type = p_r->i_type;
1084 p_uit->release.i_status = p_r->i_status;
1085 if( p_uit->i_f >= 0 )
1087 p_f = p_r->p_files + p_uit->i_f;
1088 p_uit->file.i_type = p_f->i_type;
1089 p_uit->file.psz_md5 = STRDUP( p_f->psz_md5 );
1090 p_uit->file.l_size = p_f->l_size;
1091 p_uit->file.psz_description = STRDUP( p_f->psz_description);
1092 if( p_f->psz_url[0] == '/' )
1096 asprintf( &p_uit->file.psz_url, "%s%s",
1097 p_m->psz_base_url, p_f->psz_url );
1102 p_uit->file.psz_url = STRDUP( p_f->psz_url );
1109 * Clears the iterator data (file, release and mirror structs)
1111 * \param p_uit update iterator
1114 void update_iterator_ClearData( update_iterator_t *p_uit )
1116 p_uit->file.i_type = UPDATE_FILE_TYPE_NONE;
1117 FREE( p_uit->file.psz_md5 );
1118 p_uit->file.l_size = 0;
1119 FREE( p_uit->file.psz_description );
1120 FREE( p_uit->file.psz_url );
1121 FREE( p_uit->release.psz_version );
1122 FREE( p_uit->release.psz_svn_revision );
1123 p_uit->release.i_type = UPDATE_RELEASE_TYPE_UNSTABLE;
1124 p_uit->release.i_status = UPDATE_RELEASE_STATUS_NONE;
1125 FREE( p_uit->mirror.psz_name );
1126 FREE( p_uit->mirror.psz_location );
1127 FREE( p_uit->mirror.psz_type );
1131 * Perform an action on the update iterator
1132 * Only the first matching action is performed.
1134 * \param p_uit update iterator
1135 * \param i_action update action bitmask. can be a combination of UPDATE_NEXT, UPDATE_PREV, UPDATE_MIRROR, UPDATE_RELEASE, UPDATE_FILE, UPDATE_RESET
1136 * \return UPDATE_FAIL if action fails, UPDATE_SUCCESS|(combination of UPDATE_MIRROR, UPDATE_RELEASE and UPDATE_FILE if these changed) otherwise
1138 unsigned int update_iterator_Action( update_iterator_t *p_uit, int i_action )
1140 if( i_action & UPDATE_RESET )
1142 return update_iterator_Reset( p_uit );
1145 if( i_action & UPDATE_MIRROR )
1147 if( i_action & UPDATE_PREV )
1149 return update_iterator_PrevMirror( p_uit );
1153 return update_iterator_NextMirror( p_uit );
1156 /*else if( i_action & UPDATE_RELEASE )
1158 if( i_action & UPDATE_PREV )
1160 return update_iterator_PrevRelease( p_uit );
1164 return update_iterator_NextRelease( p_uit );
1167 else if( i_action & UPDATE_FILE )
1169 if( i_action & UPDATE_PREV )
1171 return update_iterator_PrevFile( p_uit );
1175 return update_iterator_NextFile( p_uit );
1180 return UPDATE_SUCCESS;
1185 * Object to launch download thread in a different object
1189 char *psz_dest; //< Download destination
1190 char *psz_src; //< Download source
1191 char *psz_status; //< Download status displayed in progress dialog
1192 } download_thread_t;
1194 void update_download_for_real( download_thread_t *p_this );
1197 * Download the file selected by the update iterator. This function will
1198 * launch the download in a new thread (downloads can be long)
1200 * \param p_uit update iterator
1201 * \param psz_dest destination file path
1204 void update_download( update_iterator_t *p_uit, char *psz_dest )
1206 download_thread_t *p_dt =
1207 vlc_object_create( p_uit->p_u->p_vlc, sizeof( download_thread_t ) );
1209 p_dt->psz_dest = strdup( psz_dest );
1210 p_dt->psz_src = strdup( p_uit->file.psz_url );
1211 asprintf( &p_dt->psz_status, "%s - %s (%s)\nSource: %s\nDestination: %s",
1212 p_uit->file.psz_description, p_uit->release.psz_version,
1213 p_uit->release.psz_svn_revision, p_uit->file.psz_url,
1216 vlc_thread_create( p_dt, "download thread", update_download_for_real,
1217 VLC_THREAD_PRIORITY_LOW, VLC_FALSE );
1221 * Convert a long int size in bytes to a string
1223 * \param l_size the size in bytes
1224 * \return the size as a string
1226 char *size_str( long int l_size )
1230 asprintf( &psz_tmp, "%.1f GB", (float)l_size/(1<<30) );
1232 asprintf( &psz_tmp, "%.1f MB", (float)l_size/(1<<20) );
1233 else if( l_size >> 10 )
1234 asprintf( &psz_tmp, "%.1f kB", (float)l_size/(1<<10) );
1236 asprintf( &psz_tmp, "%ld B", l_size );
1241 * The true download function.
1243 * \param p_this the download_thread_t object
1246 void update_download_for_real( download_thread_t *p_this )
1248 char *psz_dest = p_this->psz_dest;
1249 char *psz_src = p_this->psz_src;
1251 vlc_t *p_vlc = p_this->p_vlc;
1253 FILE *p_file = NULL;
1259 long int l_size, l_done = 0;
1261 vlc_thread_ready( p_this );
1263 asprintf( &psz_status, "%s\nDownloading... 0.0/? %.1f%% done",
1264 p_this->psz_status, 0.0 );
1265 i_progress = intf_UserProgress( p_vlc, "Downloading...",
1268 p_stream = stream_UrlNew( p_vlc, psz_src );
1271 msg_Err( p_vlc, "Failed to open %s for reading", psz_src );
1272 intf_UserFatal( p_vlc, "Downloading...",
1273 "Failed to open %s for reading", psz_src );
1274 intf_UserHide( p_vlc, i_progress );
1279 p_file = fopen( psz_dest, "w" );
1282 msg_Err( p_vlc, "Failed to open %s for writing", psz_dest );
1283 intf_UserFatal( p_vlc, "Downloading...",
1284 "Failed to open %s for writing", psz_dest );
1285 intf_UserHide( p_vlc, i_progress );
1290 char *psz_s1; char *psz_s2;
1292 l_size = stream_Size(p_stream);
1293 p_buffer = (void *)malloc( 1<<10 );
1295 while( ( l_read = stream_Read( p_stream, p_buffer, 1<<10 ) ) )
1299 fwrite( p_buffer, l_read, 1, p_file );
1303 f_progress = 100.0*(float)l_done/(float)l_size;
1304 psz_s1 = size_str( l_done );
1305 psz_s2 = size_str( l_size );
1306 asprintf( &psz_status, "%s\nDownloading... %s/%s (%.1f%%) done",
1307 p_this->psz_status, psz_s1, psz_s2, f_progress );
1308 free( psz_s1 ); free( psz_s2 );
1310 intf_UserProgressUpdate( p_vlc, i_progress,
1311 psz_status, f_progress );
1316 stream_Delete( p_stream );
1319 psz_s2 = size_str( l_size );
1320 asprintf( &psz_status, "%s\nDone %s (100.00%%)",
1321 p_this->psz_status, psz_s2 );
1323 intf_UserProgressUpdate( p_vlc, i_progress, psz_status, 100.0 );
1328 free( p_this->psz_dest );
1329 free( p_this->psz_src );
1330 free( p_this->psz_status );
1333 CloseHandle( p_this->thread_id );
1336 vlc_object_destroy( p_this );