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 *****************************************************************************/
40 #include <ctype.h> /* tolower() */
43 #include <vlc_update.h>
45 #include <vlc_block.h>
46 #include <vlc_stream.h>
48 #include <vlc_interface.h>
49 #include <vlc_charset.h>
51 /*****************************************************************************
53 *****************************************************************************/
55 /* All release notes and source packages should match on "*"
56 * Only binary installers are OS specific ( we only provide these
57 * for Win32, Mac OS X, WincCE, beos(?) ) */
58 #if defined( UNDER_CE )
59 # define UPDATE_VLC_OS "*"
60 # define UPDATE_VLC_ARCH "*"
61 #elif defined( WIN32 )
62 # define UPDATE_VLC_OS "windows"
63 # define UPDATE_VLC_ARCH "i386"
64 #elif defined( __APPLE__ )
65 # define UPDATE_VLC_OS "macosx"
66 # if defined( __powerpc__ ) || defined( __ppc__ ) || defined( __ppc64__ )
67 # define UPDATE_VLC_ARCH "ppc"
69 # define UPDATE_VLC_ARCH "x86"
71 #elif defined( SYS_BEOS )
72 # define UPDATE_VLC_OS "beos"
73 # define UPDATE_VLC_ARCH "i386"
75 # define UPDATE_VLC_OS "*"
76 # define UPDATE_VLC_ARCH "*"
79 #define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status.xml"
80 #define UPDATE_VLC_MIRRORS_URL "http://update.videolan.org/mirrors.xml"
82 #define STRDUP( a ) ( a ? strdup( a ) : NULL )
84 /*****************************************************************************
86 *****************************************************************************/
88 void FreeMirrorsList( update_t * );
89 void FreeReleasesList( update_t * );
90 void GetMirrorsList( update_t *, vlc_bool_t );
91 void GetFilesList( update_t *, vlc_bool_t );
93 int CompareReleases( struct update_release_t *, struct update_release_t * );
94 int CompareReleaseToCurrent( struct update_release_t * );
96 unsigned int update_iterator_Reset( update_iterator_t * );
97 unsigned int update_iterator_NextFile( update_iterator_t * );
98 unsigned int update_iterator_PrevFile( update_iterator_t * );
99 unsigned int update_iterator_NextMirror( update_iterator_t * );
100 unsigned int update_iterator_PrevMirror( update_iterator_t * );
102 void update_iterator_GetData( update_iterator_t * );
103 void update_iterator_ClearData( update_iterator_t * );
105 /*****************************************************************************
107 *****************************************************************************/
110 * Create a new update VLC struct
112 * \param p_this the calling vlc_object
113 * \return pointer to new update_t or NULL
115 update_t *__update_New( vlc_object_t *p_this )
119 if( p_this == NULL ) return NULL;
121 p_update = (update_t *)malloc( sizeof( update_t ) );
122 if( !p_update ) return NULL;
124 vlc_mutex_init( p_this, &p_update->lock );
126 p_update->p_libvlc = p_this->p_libvlc;
128 p_update->p_releases = NULL;
129 p_update->i_releases = 0;
130 p_update->b_releases = VLC_FALSE;
132 p_update->p_mirrors = NULL;
133 p_update->i_mirrors = 0;
134 p_update->b_mirrors = VLC_FALSE;
137 msg_Err( p_this, "Auto-update currently disabled." );
138 vlc_mutex_destroy( &p_update->lock );
147 * Delete an update_t struct
149 * \param p_update update_t* pointer
152 void update_Delete( update_t *p_update )
154 vlc_mutex_destroy( &p_update->lock );
155 FreeMirrorsList( p_update );
156 FreeReleasesList( p_update );
161 * Empty the mirrors list
162 * *p_update should be locked before using this function
164 * \param p_update pointer to the update struct
167 void FreeMirrorsList( update_t *p_update )
171 for( i = 0; i < p_update->i_mirrors; i++ )
173 free( p_update->p_mirrors[i].psz_name );
174 free( p_update->p_mirrors[i].psz_location );
175 free( p_update->p_mirrors[i].psz_type );
176 free( p_update->p_mirrors[i].psz_base_url );
178 FREENULL( p_update->p_mirrors );
179 p_update->i_mirrors = 0;
180 p_update->b_mirrors = VLC_FALSE;
184 * Empty the releases list
185 * *p_update should be locked before calling this function
187 * \param p_update pointer to the update struct
190 void FreeReleasesList( update_t *p_update )
194 for( i = 0; i < p_update->i_releases; i++ )
197 struct update_release_t *p_release = (p_update->p_releases + i);
198 for( j = 0; j < p_release->i_files; j++ )
200 free( p_release->p_files[j].psz_md5 );
201 free( p_release->p_files[j].psz_url );
202 free( p_release->p_files[j].psz_description );
204 free( p_release->psz_major );
205 free( p_release->psz_minor );
206 free( p_release->psz_revision );
207 free( p_release->psz_extra );
208 free( p_release->psz_svn_revision );
209 free( p_release->p_files );
211 FREENULL( p_update->p_releases );
212 p_update->i_releases = 0;
213 p_update->b_releases = VLC_FALSE;
217 * Get the mirrors list XML file and parse it
218 * *p_update has to be unlocked when calling this function
220 * \param p_update pointer to the update struct
221 * \param b_force set to VLC_TRUE if you want to force the mirrors list update
224 void GetMirrorsList( update_t *p_update, vlc_bool_t b_force )
226 stream_t *p_stream = NULL;
229 xml_reader_t *p_xml_reader = NULL;
230 char *psz_eltname = NULL;
231 //char *psz_eltvalue = NULL;
232 char *psz_name = NULL;
233 char *psz_value = NULL;
234 struct update_mirror_t tmp_mirror;
236 vlc_mutex_lock( &p_update->lock );
238 memset( &tmp_mirror, 0, sizeof(struct update_mirror_t));
240 if( p_update->b_mirrors && b_force == VLC_FALSE )
242 vlc_mutex_unlock( &p_update->lock );
246 p_xml = xml_Create( p_update->p_libvlc );
249 msg_Err( p_update->p_libvlc, "Failed to open XML parser" );
253 p_stream = stream_UrlNew( p_update->p_libvlc, UPDATE_VLC_MIRRORS_URL );
256 msg_Err( p_update->p_libvlc, "Failed to open %s for reading",
257 UPDATE_VLC_MIRRORS_URL );
261 p_xml_reader = xml_ReaderCreate( p_xml, p_stream );
265 msg_Err( p_update->p_libvlc, "Failed to open %s for parsing",
266 UPDATE_VLC_MIRRORS_URL );
270 if( p_update->p_mirrors )
272 FreeMirrorsList( p_update );
275 while( xml_ReaderRead( p_xml_reader ) == 1 )
277 switch( xml_ReaderNodeType( p_xml_reader ) )
280 msg_Err( p_update->p_libvlc, "Error while parsing %s",
281 UPDATE_VLC_MIRRORS_URL );
284 case XML_READER_STARTELEM:
285 psz_eltname = xml_ReaderName( p_xml_reader );
288 msg_Err( p_update->p_libvlc, "Error while parsing %s",
289 UPDATE_VLC_MIRRORS_URL );
293 while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
295 psz_name = xml_ReaderName( p_xml_reader );
296 psz_value = xml_ReaderValue( p_xml_reader );
298 if( !psz_name || !psz_value )
300 msg_Err( p_update->p_libvlc, "Error while parsing %s",
301 UPDATE_VLC_MIRRORS_URL );
305 if( !strcmp( psz_eltname, "mirror" ) )
307 if( !strcmp( psz_name, "name" ) )
308 tmp_mirror.psz_name = STRDUP( psz_value );
309 else if( !strcmp( psz_name, "location" ) )
310 tmp_mirror.psz_location = STRDUP( psz_value );
312 else if( !strcmp( psz_eltname, "url" ) )
314 if( !strcmp( psz_name, "type" ) )
315 tmp_mirror.psz_type = STRDUP( psz_value );
316 else if( !strcmp( psz_name, "base" ) )
317 tmp_mirror.psz_base_url = STRDUP( psz_value );
319 FREENULL( psz_name );
320 FREENULL( psz_value );
322 if( !strcmp( psz_eltname, "url" ) )
324 /* append to mirrors list */
325 p_update->p_mirrors =
326 (struct update_mirror_t *)realloc( p_update->p_mirrors,
327 (++(p_update->i_mirrors))
328 *sizeof( struct update_mirror_t ) );
329 p_update->p_mirrors[ p_update->i_mirrors - 1 ] =
331 tmp_mirror.psz_name = STRDUP( tmp_mirror.psz_name );
332 tmp_mirror.psz_location = STRDUP( tmp_mirror.psz_location );
333 tmp_mirror.psz_type = NULL;
334 tmp_mirror.psz_base_url = NULL;
336 FREENULL( psz_eltname );
339 case XML_READER_ENDELEM:
340 psz_eltname = xml_ReaderName( p_xml_reader );
343 msg_Err( p_update->p_libvlc, "Error while parsing %s",
344 UPDATE_VLC_MIRRORS_URL );
348 if( !strcmp( psz_eltname, "mirror" ) )
350 FREENULL( tmp_mirror.psz_name );
351 FREENULL( tmp_mirror.psz_location );
354 FREENULL( psz_eltname );
357 /*case XML_READER_TEXT:
358 psz_eltvalue = xml_ReaderValue( p_xml_reader );
359 FREENULL( psz_eltvalue );
364 p_update->b_mirrors = VLC_TRUE;
367 vlc_mutex_unlock( &p_update->lock );
370 //free( psz_eltvalue );
374 free( tmp_mirror.psz_name );
375 free( tmp_mirror.psz_location );
376 free( tmp_mirror.psz_type );
377 free( tmp_mirror.psz_base_url );
379 if( p_xml_reader && p_xml )
380 xml_ReaderDelete( p_xml, p_xml_reader );
382 stream_Delete( p_stream );
388 * Get the files list XML file and parse it
389 * *p_update has to be unlocked when calling this function
391 * \param p_update pointer to update struct
392 * \param b_force set to VLC_TRUE if you want to force the files list update
395 void GetFilesList( update_t *p_update, vlc_bool_t b_force )
397 stream_t *p_stream = NULL;
400 xml_reader_t *p_xml_reader = NULL;
402 char *psz_eltname = NULL;
403 char *psz_eltvalue = NULL;
404 char *psz_name = NULL;
405 char *psz_value = NULL;
407 struct update_release_t *p_release = NULL;
408 struct update_release_t tmp_release;
409 struct update_file_t tmp_file;
411 vlc_bool_t b_os = VLC_FALSE, b_arch = VLC_FALSE;
413 memset( &tmp_release, 0, sizeof(struct update_release_t) );
414 memset( &tmp_file, 0, sizeof(struct update_file_t) );
416 tmp_release.i_type = UPDATE_RELEASE_TYPE_STABLE;
418 vlc_mutex_lock( &p_update->lock );
420 if( p_update->b_releases && b_force == VLC_FALSE )
422 vlc_mutex_unlock( &p_update->lock );
426 p_xml = xml_Create( p_update->p_libvlc );
429 msg_Err( p_update->p_libvlc, "Failed to open XML parser" );
433 p_stream = stream_UrlNew( p_update->p_libvlc, UPDATE_VLC_STATUS_URL );
436 msg_Err( p_update->p_libvlc, "Failed to open %s for reading",
437 UPDATE_VLC_STATUS_URL );
441 p_xml_reader = xml_ReaderCreate( p_xml, p_stream );
445 msg_Err( p_update->p_libvlc, "Failed to open %s for parsing",
446 UPDATE_VLC_STATUS_URL );
450 if( p_update->p_releases )
452 FreeReleasesList( p_update );
455 while( xml_ReaderRead( p_xml_reader ) == 1 )
457 switch( xml_ReaderNodeType( p_xml_reader ) )
460 msg_Err( p_update->p_libvlc, "Error while parsing %s",
461 UPDATE_VLC_STATUS_URL );
464 case XML_READER_STARTELEM:
465 psz_eltname = xml_ReaderName( p_xml_reader );
468 msg_Err( p_update->p_libvlc, "Error while parsing %s",
469 UPDATE_VLC_STATUS_URL );
473 while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
475 psz_name = xml_ReaderName( p_xml_reader );
476 psz_value = xml_ReaderValue( p_xml_reader );
478 if( !psz_name || !psz_value )
480 msg_Err( p_update->p_libvlc, "Error while parsing %s",
481 UPDATE_VLC_STATUS_URL );
487 if( strcmp( psz_eltname, "version" ) == 0 )
489 if( !strcmp( psz_name, "major" ) )
490 tmp_release.psz_major = STRDUP( psz_value );
491 else if( !strcmp( psz_name, "minor" ) )
492 tmp_release.psz_minor = STRDUP( psz_value );
493 else if( !strcmp( psz_name, "revision" ) )
494 tmp_release.psz_revision = STRDUP( psz_value );
495 else if( !strcmp( psz_name, "extra" ) )
496 tmp_release.psz_extra = STRDUP( psz_value );
497 else if( !strcmp( psz_name, "svn" ) )
498 tmp_release.psz_svn_revision =
500 else if( !strcmp( psz_name, "version" ) )
502 if( !strcmp( psz_value, "unstable" ) )
504 UPDATE_RELEASE_TYPE_UNSTABLE;
505 else if( !strcmp( psz_value, "testing" ) )
507 UPDATE_RELEASE_TYPE_TESTING;
510 UPDATE_RELEASE_TYPE_STABLE;
513 else if( !strcmp( psz_eltname, "file" ) )
515 if( !strcmp( psz_name, "type" ) )
517 if( !strcmp( psz_value, "info" ) )
518 tmp_file.i_type = UPDATE_FILE_TYPE_INFO;
519 else if( !strcmp( psz_value, "source" ) )
520 tmp_file.i_type = UPDATE_FILE_TYPE_SOURCE;
521 else if( !strcmp( psz_value, "binary" ) )
522 tmp_file.i_type = UPDATE_FILE_TYPE_BINARY;
523 else if( !strcmp( psz_value, "plugin" ) )
524 tmp_file.i_type = UPDATE_FILE_TYPE_PLUGIN;
526 tmp_file.i_type = UPDATE_FILE_TYPE_UNDEF;
528 else if( !strcmp( psz_name, "md5" ) )
529 tmp_file.psz_md5 = STRDUP( psz_value );
530 else if( !strcmp( psz_name, "size" ) )
531 tmp_file.l_size = atol( psz_value );
532 else if( !strcmp( psz_name, "url" ) )
533 tmp_file.psz_url = STRDUP( psz_value );
536 if( !strcmp( psz_name, "name" )
537 && ( !strcmp( psz_value, UPDATE_VLC_OS )
538 || !strcmp( psz_value, "*" ) )
539 && !strcmp( psz_eltname, "os" ) )
543 if( b_os && !strcmp( psz_name, "name" )
544 && ( !strcmp( psz_value, UPDATE_VLC_ARCH )
545 || !strcmp( psz_value, "*" ) )
546 && !strcmp( psz_eltname, "arch" ) )
550 FREENULL( psz_name );
551 FREENULL( psz_value );
553 if( ( b_os && b_arch && strcmp( psz_eltname, "arch" ) ) )
555 if( !strcmp( psz_eltname, "version" ) )
558 /* look for a previous occurrence of this release */
559 for( i = 0; i < p_update->i_releases; i++ )
561 p_release = p_update->p_releases + i;
562 if( CompareReleases( p_release, &tmp_release )
563 == UPDATE_RELEASE_STATUS_EQUAL )
568 /* if this is the first time that we see this release,
569 * append it to the list of releases */
570 if( i == p_update->i_releases )
572 tmp_release.i_status =
573 CompareReleaseToCurrent( &tmp_release );
574 p_update->p_releases =
575 (struct update_release_t *)realloc( p_update->p_releases,
576 (++(p_update->i_releases))*sizeof( struct update_release_t ) );
577 p_update->p_releases[ p_update->i_releases - 1 ] =
580 p_update->p_releases + p_update->i_releases - 1;
581 tmp_release.psz_major = NULL;
582 tmp_release.psz_minor = NULL;
583 tmp_release.psz_revision = NULL;
584 tmp_release.psz_extra = NULL;
585 tmp_release.psz_svn_revision = NULL;
586 tmp_release.i_type = UPDATE_RELEASE_TYPE_STABLE;
587 tmp_release.i_status = 0;
588 tmp_release.p_files = NULL;
589 tmp_release.i_files = 0;
593 FREENULL( tmp_release.psz_major );
594 FREENULL( tmp_release.psz_minor );
595 FREENULL( tmp_release.psz_revision );
596 FREENULL( tmp_release.psz_extra );
597 FREENULL( tmp_release.psz_svn_revision );
598 tmp_release.i_type = UPDATE_RELEASE_TYPE_STABLE;
599 FREENULL( tmp_release.p_files );
600 tmp_release.i_files = 0;
603 else if( !strcmp( psz_eltname, "file" ) )
605 /* append file to p_release's file list */
606 if( p_release == NULL )
611 (struct update_file_t *)realloc( p_release->p_files,
612 (++(p_release->i_files))*sizeof( struct update_file_t ) );
613 p_release->p_files[ p_release->i_files - 1 ] = tmp_file;
614 tmp_file.i_type = UPDATE_FILE_TYPE_UNDEF;
615 tmp_file.psz_md5 = NULL;
617 tmp_file.psz_url = NULL;
618 tmp_file.psz_description = NULL;
621 FREENULL( psz_eltname );
624 case XML_READER_ENDELEM:
625 psz_eltname = xml_ReaderName( p_xml_reader );
628 msg_Err( p_update->p_libvlc, "Error while parsing %s",
629 UPDATE_VLC_STATUS_URL );
633 if( !strcmp( psz_eltname, "os" ) )
635 else if( !strcmp( psz_eltname, "arch" ) )
637 FREENULL( psz_eltname );
640 case XML_READER_TEXT:
641 psz_eltvalue = xml_ReaderValue( p_xml_reader );
642 if( p_release && p_release->i_files )
643 p_release->p_files[ p_release->i_files - 1 ]
644 .psz_description = STRDUP( psz_eltvalue );
645 FREENULL( psz_eltvalue );
650 p_update->b_releases = VLC_TRUE;
653 vlc_mutex_unlock( &p_update->lock );
656 free( psz_eltvalue );
660 free( tmp_release.psz_major );
661 free( tmp_release.psz_minor );
662 free( tmp_release.psz_revision );
663 free( tmp_release.psz_extra );
664 free( tmp_release.psz_svn_revision );
666 free( tmp_file.psz_md5 );
667 free( tmp_file.psz_url );
668 free( tmp_file.psz_description );
670 if( p_xml_reader && p_xml )
671 xml_ReaderDelete( p_xml, p_xml_reader );
673 stream_Delete( p_stream );
681 * \param p_update pointer to update struct
682 * \param b_force set to VLC_TRUE if you want to force the update
685 void update_Check( update_t *p_update, vlc_bool_t b_force )
687 if( p_update == NULL ) return;
688 GetMirrorsList( p_update, b_force );
689 GetFilesList( p_update, b_force );
693 * Compare two release numbers
694 * The comparision algorith basically performs an alphabetical order (strcmp)
695 * comparision of each of the version number elements until it finds two
696 * different ones. This is the tricky function.
698 * \param p1 first release
699 * \param p2 second release
700 * \return like strcmp
702 int CompareReleases( struct update_release_t *p1, struct update_release_t *p2 )
705 if( ( d = strcmp( p1->psz_major, p2->psz_major ) ) ) ;
706 else if( ( d = strcmp( p1->psz_minor, p2->psz_minor ) ) ) ;
707 else if( ( d = strcmp( p1->psz_revision, p2->psz_revision ) ) ) ;
710 d = strcmp( p1->psz_extra, p2->psz_extra );
714 * not num < NULL < num
715 * -test and -svn releases are thus always considered older than
716 * -'' or -0 releases, which is the best i could come up with */
719 strtol( p1->psz_extra, &psz_end1, 10 );
720 strtol( p2->psz_extra, &psz_end2, 10 );
721 if( psz_end2 == p2->psz_extra
722 && ( psz_end1 != p1->psz_extra || *p1->psz_extra == '\0' ) )
727 return UPDATE_RELEASE_STATUS_OLDER;
729 return UPDATE_RELEASE_STATUS_EQUAL;
731 return UPDATE_RELEASE_STATUS_NEWER;
735 * Compare a given release's version number to the current VLC's one
738 * \return >0 if newer, 0 if equal and <0 if older
740 int CompareReleaseToCurrent( struct update_release_t *p )
742 struct update_release_t c;
745 memset( &c, 0, sizeof(struct update_release_t) );
746 c.psz_major = STRDUP( PACKAGE_VERSION_MAJOR );
747 c.psz_minor = STRDUP( PACKAGE_VERSION_MINOR );
748 c.psz_revision = STRDUP( PACKAGE_VERSION_REVISION );
749 c.psz_extra = STRDUP( PACKAGE_VERSION_EXTRA );
750 r = CompareReleases( p, &c );
753 free( c.psz_revision );
758 /*****************************************************************************
759 * Updatei_iterator_t functions
760 *****************************************************************************/
763 * Create a new update iterator structure. This structure can then be used to
764 * describe a position and move through the update and mirror trees/lists.
765 * This will use an existing update struct or create a new one if none is
768 * \param p_u the calling update_t
769 * \return a pointer to an update iterator
771 update_iterator_t *update_iterator_New( update_t *p_u )
773 update_iterator_t *p_uit = NULL;
778 p_uit = (update_iterator_t *)malloc( sizeof( update_iterator_t ) );
779 if( p_uit == NULL ) return NULL;
787 p_uit->i_t = UPDATE_FILE_TYPE_ALL;
788 p_uit->i_rs = UPDATE_RELEASE_STATUS_ALL;
789 p_uit->i_rt = UPDATE_RELEASE_TYPE_STABLE;
791 p_uit->file.i_type = UPDATE_FILE_TYPE_NONE;
792 p_uit->file.psz_md5 = NULL;
793 p_uit->file.psz_url = NULL;
794 p_uit->file.l_size = 0;
795 p_uit->file.psz_description = NULL;
797 p_uit->release.psz_version = NULL;
798 p_uit->release.psz_svn_revision = NULL;
799 p_uit->release.i_type = UPDATE_RELEASE_TYPE_UNSTABLE;
800 p_uit->release.i_status = UPDATE_RELEASE_STATUS_NONE;
802 p_uit->mirror.psz_name = NULL;
803 p_uit->mirror.psz_location = NULL;
804 p_uit->mirror.psz_type = NULL;
810 * Delete an update iterator structure (duh!)
812 * \param p_uit pointer to an update iterator
815 void update_iterator_Delete( update_iterator_t *p_uit )
818 update_iterator_ClearData( p_uit );
823 * Reset an update_iterator_t structure
825 * \param p_uit pointer to an update iterator
826 * \return UPDATE_FAIL upon error, UPDATE_SUCCESS otherwise
828 unsigned int update_iterator_Reset( update_iterator_t *p_uit )
830 if( !p_uit ) return UPDATE_FAIL;
836 update_iterator_ClearData( p_uit );
837 return UPDATE_SUCCESS;
841 * Finds the next file in the update tree that matches status and type
842 * requirements set in the update_iterator
844 * \param p_uit update iterator
845 * \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
847 unsigned int update_iterator_NextFile( update_iterator_t *p_uit )
851 if( !p_uit ) return UPDATE_FAIL;
855 /* if the update iterator was already in a "no match" state, start over */
856 if( p_uit->i_r == -1 ) p_uit->i_r = 0;
857 //if( p_uit->i_f == -1 ) p_uit->i_f = 0;
859 vlc_mutex_lock( &p_uit->p_u->lock );
861 for( r = p_uit->i_r; r < p_uit->p_u->i_releases; r++ )
863 if( !( p_uit->p_u->p_releases[r].i_status & p_uit->i_rs ) ) continue;
864 for( f = ( r == p_uit->i_r ? p_uit->i_f + 1 : 0 );
865 f < p_uit->p_u->p_releases[r].i_files; f++ )
867 if( p_uit->p_u->p_releases[r].p_files[f].i_type & p_uit->i_t )
869 goto done;/* "double break" */
877 r = p_uit->p_u->i_releases;
879 if( old_r == p_uit->i_r )
881 update_iterator_GetData( p_uit );
882 vlc_mutex_unlock( &p_uit->p_u->lock );
883 return UPDATE_SUCCESS|UPDATE_FILE;
885 else if( p_uit->i_r == r )
889 update_iterator_GetData( p_uit );
890 vlc_mutex_unlock( &p_uit->p_u->lock );
895 update_iterator_GetData( p_uit );
896 vlc_mutex_unlock( &p_uit->p_u->lock );
897 return UPDATE_SUCCESS|UPDATE_RELEASE|UPDATE_FILE;
902 * Finds the previous file in the update tree that matches status and type
903 * requirements set in the update_iterator
905 * \param p_uit update iterator
906 * \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
909 unsigned int update_iterator_PrevFile( update_iterator_t *p_uit )
913 if( !p_uit ) return UPDATE_FAIL;
917 /* if the update iterator was already in a "no match" state, start over
918 * (begin at the end of the list) */
919 if( p_uit->i_r == -1 ) p_uit->i_r = p_uit->p_u->i_releases - 1;
920 p_uit->i_f = p_uit->p_u->p_releases[p_uit->i_r].i_files + 1;
922 vlc_mutex_lock( &p_uit->p_u->lock );
924 for( r = p_uit->i_r; r >= 0; r-- )
926 if( !( p_uit->p_u->p_releases[r].i_status & p_uit->i_rs ) ) continue;
927 for( f =( r==p_uit->i_r ? p_uit->i_f - 1 : p_uit->p_u->p_releases[r].i_files );
930 if( p_uit->p_u->p_releases[r].p_files[f].i_type & p_uit->i_t )
932 goto done;/* "double break" */
940 r = p_uit->p_u->i_releases;
942 if( old_r == p_uit->i_r )
944 update_iterator_GetData( p_uit );
945 vlc_mutex_unlock( &p_uit->p_u->lock );
946 return UPDATE_SUCCESS|UPDATE_FILE;
948 else if( p_uit->i_r == -1 )
952 update_iterator_GetData( p_uit );
953 vlc_mutex_unlock( &p_uit->p_u->lock );
958 update_iterator_GetData( p_uit );
959 vlc_mutex_unlock( &p_uit->p_u->lock );
960 return UPDATE_SUCCESS|UPDATE_RELEASE|UPDATE_FILE;
965 * Finds the next mirror in the update tree
967 * \param update iterator
968 * \return UPDATE_FAIL if we can't find the next mirror, UPDATE_SUCCESS|UPDATE_MIRROR otherwise
970 unsigned int update_iterator_NextMirror( update_iterator_t *p_uit )
972 if( !p_uit ) return UPDATE_FAIL;
973 vlc_mutex_lock( &p_uit->p_u->lock );
975 if( p_uit->i_m >= p_uit->p_u->i_mirrors ) p_uit->i_m = -1;
976 update_iterator_GetData( p_uit );
977 vlc_mutex_unlock( &p_uit->p_u->lock );
978 return p_uit->i_m == -1 ? UPDATE_FAIL : UPDATE_SUCCESS|UPDATE_MIRROR;
982 * Finds the previous mirror in the update tree
984 * \param update iterator
985 * \return UPDATE_FAIL if we can't find a previous mirror, UPDATE_SUCCESS|UPDATE_MIRROR otherwise
987 unsigned int update_iterator_PrevMirror( update_iterator_t *p_uit )
989 if( !p_uit ) return UPDATE_FAIL;
990 vlc_mutex_lock( &p_uit->p_u->lock );
992 update_iterator_GetData( p_uit );
993 vlc_mutex_unlock( &p_uit->p_u->lock );
994 return p_uit->i_m == -1 ? UPDATE_FAIL : UPDATE_SUCCESS|UPDATE_MIRROR;
998 * Change the update iterator's position in the file and mirrors tree
999 * If position is negative, don't change it
1001 * \param i_m position in mirrors list
1002 * \param i_r position in releases list
1003 * \param i_f position in release's files list
1004 * \return UPDATE_FAIL when changing position fails or position wasn't changed, a combination of UPDATE_MIRROR, UPDATE_RELEASE and UPDATE_FILE otherwise
1006 unsigned int update_iterator_ChooseMirrorAndFile( update_iterator_t *p_uit,
1007 int i_m, int i_r, int i_f )
1009 unsigned int i_val = 0;
1011 if( !p_uit ) return 0;
1012 vlc_mutex_lock( &p_uit->p_u->lock );
1016 if( i_m < p_uit->p_u->i_mirrors )
1018 if( i_m != p_uit->i_m )
1019 i_val |= UPDATE_MIRROR;
1027 if( i_r < p_uit->p_u->i_releases )
1029 if( i_r != p_uit->i_r )
1030 i_val |= UPDATE_FILE;
1038 if( i_r >= 0 && i_r < p_uit->p_u->i_releases
1039 && i_f < p_uit->p_u->p_releases[p_uit->i_r].i_files )
1041 if( i_f != p_uit->i_f )
1042 i_val |= UPDATE_FILE;
1048 update_iterator_GetData( p_uit );
1049 vlc_mutex_unlock( &p_uit->p_u->lock );
1051 if( ( i_m < 0 || p_uit->i_m >= 0 )
1052 && ( i_r < 0 || p_uit->i_r >= 0 )
1053 && ( i_f < 0 || p_uit->i_f >= 0 ) )
1055 /* Everything worked */
1056 return UPDATE_SUCCESS|i_val;
1060 /* Something failed */
1066 * Fills the iterator data (file, release and mirror structs)
1067 * The update struct should be locked before calling this function.
1069 * \param p_uit update iterator
1072 void update_iterator_GetData( update_iterator_t *p_uit )
1074 struct update_release_t *p_r = NULL;
1075 struct update_file_t *p_f = NULL;
1076 struct update_mirror_t *p_m = NULL;
1078 update_iterator_ClearData( p_uit );
1080 if( p_uit->i_m >= 0 )
1082 p_m = p_uit->p_u->p_mirrors + p_uit->i_m;
1083 p_uit->mirror.psz_name = STRDUP( p_m->psz_name );
1084 p_uit->mirror.psz_location = STRDUP( p_m->psz_location );
1085 p_uit->mirror.psz_type = STRDUP( p_m->psz_type );
1088 if( p_uit->i_r >= 0 )
1090 p_r = p_uit->p_u->p_releases + p_uit->i_r;
1091 asprintf( &p_uit->release.psz_version, "%s.%s.%s-%s",
1096 p_uit->release.psz_svn_revision = STRDUP( p_r->psz_svn_revision );
1097 p_uit->release.i_type = p_r->i_type;
1098 p_uit->release.i_status = p_r->i_status;
1099 if( p_uit->i_f >= 0 )
1101 p_f = p_r->p_files + p_uit->i_f;
1102 p_uit->file.i_type = p_f->i_type;
1103 p_uit->file.psz_md5 = STRDUP( p_f->psz_md5 );
1104 p_uit->file.l_size = p_f->l_size;
1105 p_uit->file.psz_description = STRDUP( p_f->psz_description);
1106 if( p_f->psz_url[0] == '/' )
1110 asprintf( &p_uit->file.psz_url, "%s%s",
1111 p_m->psz_base_url, p_f->psz_url );
1116 p_uit->file.psz_url = STRDUP( p_f->psz_url );
1123 * Clears the iterator data (file, release and mirror structs)
1125 * \param p_uit update iterator
1128 void update_iterator_ClearData( update_iterator_t *p_uit )
1130 p_uit->file.i_type = UPDATE_FILE_TYPE_NONE;
1131 FREENULL( p_uit->file.psz_md5 );
1132 p_uit->file.l_size = 0;
1133 FREENULL( p_uit->file.psz_description );
1134 FREENULL( p_uit->file.psz_url );
1135 FREENULL( p_uit->release.psz_version );
1136 FREENULL( p_uit->release.psz_svn_revision );
1137 p_uit->release.i_type = UPDATE_RELEASE_TYPE_UNSTABLE;
1138 p_uit->release.i_status = UPDATE_RELEASE_STATUS_NONE;
1139 FREENULL( p_uit->mirror.psz_name );
1140 FREENULL( p_uit->mirror.psz_location );
1141 FREENULL( p_uit->mirror.psz_type );
1145 * Perform an action on the update iterator
1146 * Only the first matching action is performed.
1148 * \param p_uit update iterator
1149 * \param i_action update action bitmask. can be a combination of UPDATE_NEXT, UPDATE_PREV, UPDATE_MIRROR, UPDATE_RELEASE, UPDATE_FILE, UPDATE_RESET
1150 * \return UPDATE_FAIL if action fails, UPDATE_SUCCESS|(combination of UPDATE_MIRROR, UPDATE_RELEASE and UPDATE_FILE if these changed) otherwise
1152 unsigned int update_iterator_Action( update_iterator_t *p_uit, int i_action )
1154 if( i_action & UPDATE_RESET )
1156 return update_iterator_Reset( p_uit );
1159 if( i_action & UPDATE_MIRROR )
1161 if( i_action & UPDATE_PREV )
1163 return update_iterator_PrevMirror( p_uit );
1167 return update_iterator_NextMirror( p_uit );
1170 /*else if( i_action & UPDATE_RELEASE )
1172 if( i_action & UPDATE_PREV )
1174 return update_iterator_PrevRelease( p_uit );
1178 return update_iterator_NextRelease( p_uit );
1181 else if( i_action & UPDATE_FILE )
1183 if( i_action & UPDATE_PREV )
1185 return update_iterator_PrevFile( p_uit );
1189 return update_iterator_NextFile( p_uit );
1194 return UPDATE_SUCCESS;
1199 * Object to launch download thread in a different object
1203 char *psz_dest; //< Download destination
1204 char *psz_src; //< Download source
1205 char *psz_status; //< Download status displayed in progress dialog
1206 } download_thread_t;
1208 void update_download_for_real( download_thread_t *p_this );
1211 * Download the file selected by the update iterator. This function will
1212 * launch the download in a new thread (downloads can be long)
1214 * \param p_uit update iterator
1215 * \param psz_dest destination file path
1218 void update_download( update_iterator_t *p_uit, const char *psz_dest )
1220 download_thread_t *p_dt =
1221 vlc_object_create( p_uit->p_u->p_libvlc, sizeof( download_thread_t ) );
1223 p_dt->psz_dest = strdup( psz_dest );
1224 p_dt->psz_src = strdup( p_uit->file.psz_url );
1225 asprintf( &p_dt->psz_status, "%s - %s (%s)\nSource: %s\nDestination: %s",
1226 p_uit->file.psz_description, p_uit->release.psz_version,
1227 p_uit->release.psz_svn_revision, p_uit->file.psz_url,
1230 vlc_thread_create( p_dt, "download thread", update_download_for_real,
1231 VLC_THREAD_PRIORITY_LOW, VLC_FALSE );
1235 * Convert a long int size in bytes to a string
1237 * \param l_size the size in bytes
1238 * \return the size as a string
1240 static char *size_str( long int l_size )
1244 asprintf( &psz_tmp, "%.1f GB", (float)l_size/(1<<30) );
1246 asprintf( &psz_tmp, "%.1f MB", (float)l_size/(1<<20) );
1247 else if( l_size >> 10 )
1248 asprintf( &psz_tmp, "%.1f kB", (float)l_size/(1<<10) );
1250 asprintf( &psz_tmp, "%ld B", l_size );
1255 * The true download function.
1257 * \param p_this the download_thread_t object
1260 void update_download_for_real( download_thread_t *p_this )
1262 char *psz_dest = p_this->psz_dest;
1263 char *psz_src = p_this->psz_src;
1265 libvlc_int_t *p_libvlc = p_this->p_libvlc;
1267 FILE *p_file = NULL;
1273 long int l_size, l_done = 0;
1275 vlc_thread_ready( p_this );
1277 asprintf( &psz_status, "%s\nDownloading... 0.0/? %.1f%% done",
1278 p_this->psz_status, 0.0 );
1279 i_progress = intf_UserProgress( p_libvlc, "Downloading...",
1280 psz_status, 0.0, 0 );
1282 p_stream = stream_UrlNew( p_libvlc, psz_src );
1285 msg_Err( p_libvlc, "Failed to open %s for reading", psz_src );
1286 intf_UserFatal( p_libvlc, VLC_TRUE, "Error while Downloading...",
1287 "VLC failed to open %s for reading.", psz_src );
1288 intf_UserHide( p_libvlc, i_progress );
1293 p_file = utf8_fopen( psz_dest, "w" );
1296 msg_Err( p_libvlc, "Failed to open %s for writing", psz_dest );
1297 intf_UserFatal( p_libvlc, VLC_TRUE, "Error while Downloading...",
1298 "VLC failed to open %s for writing.", psz_dest );
1299 intf_UserHide( p_libvlc, i_progress );
1304 char *psz_s1; char *psz_s2;
1306 l_size = stream_Size(p_stream);
1307 p_buffer = (void *)malloc( 1<<10 );
1309 while( ( l_read = stream_Read( p_stream, p_buffer, 1<<10 ) ) )
1313 fwrite( p_buffer, l_read, 1, p_file );
1317 f_progress = 100.0*(float)l_done/(float)l_size;
1318 psz_s1 = size_str( l_done );
1319 psz_s2 = size_str( l_size );
1320 asprintf( &psz_status, "%s\nDownloading... %s/%s (%.1f%%) done",
1321 p_this->psz_status, psz_s1, psz_s2, f_progress );
1322 free( psz_s1 ); free( psz_s2 );
1324 intf_ProgressUpdate( p_libvlc, i_progress,
1325 psz_status, f_progress, 0 );
1330 stream_Delete( p_stream );
1333 psz_s2 = size_str( l_size );
1334 asprintf( &psz_status, "%s\nDone %s (100.00%%)",
1335 p_this->psz_status, psz_s2 );
1337 intf_ProgressUpdate( p_libvlc, i_progress, psz_status, 100.0, 0 );
1342 free( p_this->psz_dest );
1343 free( p_this->psz_src );
1344 free( p_this->psz_status );
1346 vlc_object_destroy( p_this );