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 ) );
123 vlc_mutex_init( p_this, &p_update->lock );
125 p_update->p_libvlc = p_this->p_libvlc;
127 p_update->p_releases = NULL;
128 p_update->i_releases = 0;
129 p_update->b_releases = VLC_FALSE;
131 p_update->p_mirrors = NULL;
132 p_update->i_mirrors = 0;
133 p_update->b_mirrors = VLC_FALSE;
136 msg_Err( p_this, "Auto-update currently disabled." );
137 vlc_mutex_destroy( &p_update->lock );
146 * Delete an update_t struct
148 * \param p_update update_t* pointer
151 void update_Delete( update_t *p_update )
153 vlc_mutex_destroy( &p_update->lock );
154 FreeMirrorsList( p_update );
155 FreeReleasesList( p_update );
160 * Empty the mirrors list
161 * *p_update should be locked before using this function
163 * \param p_update pointer to the update struct
166 void FreeMirrorsList( update_t *p_update )
170 for( i = 0; i < p_update->i_mirrors; i++ )
172 free( p_update->p_mirrors[i].psz_name );
173 free( p_update->p_mirrors[i].psz_location );
174 free( p_update->p_mirrors[i].psz_type );
175 free( p_update->p_mirrors[i].psz_base_url );
177 FREENULL( p_update->p_mirrors );
178 p_update->i_mirrors = 0;
179 p_update->b_mirrors = VLC_FALSE;
183 * Empty the releases list
184 * *p_update should be locked before calling this function
186 * \param p_update pointer to the update struct
189 void FreeReleasesList( update_t *p_update )
193 for( i = 0; i < p_update->i_releases; i++ )
196 struct update_release_t *p_release = (p_update->p_releases + i);
197 for( j = 0; j < p_release->i_files; j++ )
199 free( p_release->p_files[j].psz_md5 );
200 free( p_release->p_files[j].psz_url );
201 free( p_release->p_files[j].psz_description );
203 free( p_release->psz_major );
204 free( p_release->psz_minor );
205 free( p_release->psz_revision );
206 free( p_release->psz_extra );
207 free( p_release->psz_svn_revision );
208 free( p_release->p_files );
210 FREENULL( p_update->p_releases );
211 p_update->i_releases = 0;
212 p_update->b_releases = VLC_FALSE;
216 * Get the mirrors list XML file and parse it
217 * *p_update has to be unlocked when calling this function
219 * \param p_update pointer to the update struct
220 * \param b_force set to VLC_TRUE if you want to force the mirrors list update
223 void GetMirrorsList( update_t *p_update, vlc_bool_t b_force )
225 stream_t *p_stream = NULL;
228 xml_reader_t *p_xml_reader = NULL;
229 char *psz_eltname = NULL;
230 //char *psz_eltvalue = NULL;
231 char *psz_name = NULL;
232 char *psz_value = NULL;
233 struct update_mirror_t tmp_mirror;
235 vlc_mutex_lock( &p_update->lock );
237 memset( &tmp_mirror, 0, sizeof(struct update_mirror_t));
239 if( p_update->b_mirrors && b_force == VLC_FALSE )
241 vlc_mutex_unlock( &p_update->lock );
245 p_xml = xml_Create( p_update->p_libvlc );
248 msg_Err( p_update->p_libvlc, "Failed to open XML parser" );
252 p_stream = stream_UrlNew( p_update->p_libvlc, UPDATE_VLC_MIRRORS_URL );
255 msg_Err( p_update->p_libvlc, "Failed to open %s for reading",
256 UPDATE_VLC_MIRRORS_URL );
260 p_xml_reader = xml_ReaderCreate( p_xml, p_stream );
264 msg_Err( p_update->p_libvlc, "Failed to open %s for parsing",
265 UPDATE_VLC_MIRRORS_URL );
269 if( p_update->p_mirrors )
271 FreeMirrorsList( p_update );
274 while( xml_ReaderRead( p_xml_reader ) == 1 )
276 switch( xml_ReaderNodeType( p_xml_reader ) )
279 msg_Err( p_update->p_libvlc, "Error while parsing %s",
280 UPDATE_VLC_MIRRORS_URL );
283 case XML_READER_STARTELEM:
284 psz_eltname = xml_ReaderName( p_xml_reader );
287 msg_Err( p_update->p_libvlc, "Error while parsing %s",
288 UPDATE_VLC_MIRRORS_URL );
292 while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
294 psz_name = xml_ReaderName( p_xml_reader );
295 psz_value = xml_ReaderValue( p_xml_reader );
297 if( !psz_name || !psz_value )
299 msg_Err( p_update->p_libvlc, "Error while parsing %s",
300 UPDATE_VLC_MIRRORS_URL );
304 if( !strcmp( psz_eltname, "mirror" ) )
306 if( !strcmp( psz_name, "name" ) )
307 tmp_mirror.psz_name = STRDUP( psz_value );
308 else if( !strcmp( psz_name, "location" ) )
309 tmp_mirror.psz_location = STRDUP( psz_value );
311 else if( !strcmp( psz_eltname, "url" ) )
313 if( !strcmp( psz_name, "type" ) )
314 tmp_mirror.psz_type = STRDUP( psz_value );
315 else if( !strcmp( psz_name, "base" ) )
316 tmp_mirror.psz_base_url = STRDUP( psz_value );
318 FREENULL( psz_name );
319 FREENULL( psz_value );
321 if( !strcmp( psz_eltname, "url" ) )
323 /* append to mirrors list */
324 p_update->p_mirrors =
325 (struct update_mirror_t *)realloc( p_update->p_mirrors,
326 (++(p_update->i_mirrors))
327 *sizeof( struct update_mirror_t ) );
328 p_update->p_mirrors[ p_update->i_mirrors - 1 ] =
330 tmp_mirror.psz_name = STRDUP( tmp_mirror.psz_name );
331 tmp_mirror.psz_location = STRDUP( tmp_mirror.psz_location );
332 tmp_mirror.psz_type = NULL;
333 tmp_mirror.psz_base_url = NULL;
335 FREENULL( psz_eltname );
338 case XML_READER_ENDELEM:
339 psz_eltname = xml_ReaderName( p_xml_reader );
342 msg_Err( p_update->p_libvlc, "Error while parsing %s",
343 UPDATE_VLC_MIRRORS_URL );
347 if( !strcmp( psz_eltname, "mirror" ) )
349 FREENULL( tmp_mirror.psz_name );
350 FREENULL( tmp_mirror.psz_location );
353 FREENULL( psz_eltname );
356 /*case XML_READER_TEXT:
357 psz_eltvalue = xml_ReaderValue( p_xml_reader );
358 FREENULL( psz_eltvalue );
363 p_update->b_mirrors = VLC_TRUE;
366 vlc_mutex_unlock( &p_update->lock );
369 //free( psz_eltvalue );
373 free( tmp_mirror.psz_name );
374 free( tmp_mirror.psz_location );
375 free( tmp_mirror.psz_type );
376 free( tmp_mirror.psz_base_url );
378 if( p_xml_reader && p_xml )
379 xml_ReaderDelete( p_xml, p_xml_reader );
381 stream_Delete( p_stream );
387 * Get the files list XML file and parse it
388 * *p_update has to be unlocked when calling this function
390 * \param p_update pointer to update struct
391 * \param b_force set to VLC_TRUE if you want to force the files list update
394 void GetFilesList( update_t *p_update, vlc_bool_t b_force )
396 stream_t *p_stream = NULL;
399 xml_reader_t *p_xml_reader = NULL;
401 char *psz_eltname = NULL;
402 char *psz_eltvalue = NULL;
403 char *psz_name = NULL;
404 char *psz_value = NULL;
406 struct update_release_t *p_release = NULL;
407 struct update_release_t tmp_release;
408 struct update_file_t tmp_file;
410 vlc_bool_t b_os = VLC_FALSE, b_arch = VLC_FALSE;
412 memset( &tmp_release, 0, sizeof(struct update_release_t) );
413 memset( &tmp_file, 0, sizeof(struct update_file_t) );
415 tmp_release.i_type = UPDATE_RELEASE_TYPE_STABLE;
417 vlc_mutex_lock( &p_update->lock );
419 if( p_update->b_releases && b_force == VLC_FALSE )
421 vlc_mutex_unlock( &p_update->lock );
425 p_xml = xml_Create( p_update->p_libvlc );
428 msg_Err( p_update->p_libvlc, "Failed to open XML parser" );
432 p_stream = stream_UrlNew( p_update->p_libvlc, UPDATE_VLC_STATUS_URL );
435 msg_Err( p_update->p_libvlc, "Failed to open %s for reading",
436 UPDATE_VLC_STATUS_URL );
440 p_xml_reader = xml_ReaderCreate( p_xml, p_stream );
444 msg_Err( p_update->p_libvlc, "Failed to open %s for parsing",
445 UPDATE_VLC_STATUS_URL );
449 if( p_update->p_releases )
451 FreeReleasesList( p_update );
454 while( xml_ReaderRead( p_xml_reader ) == 1 )
456 switch( xml_ReaderNodeType( p_xml_reader ) )
459 msg_Err( p_update->p_libvlc, "Error while parsing %s",
460 UPDATE_VLC_STATUS_URL );
463 case XML_READER_STARTELEM:
464 psz_eltname = xml_ReaderName( p_xml_reader );
467 msg_Err( p_update->p_libvlc, "Error while parsing %s",
468 UPDATE_VLC_STATUS_URL );
472 while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
474 psz_name = xml_ReaderName( p_xml_reader );
475 psz_value = xml_ReaderValue( p_xml_reader );
477 if( !psz_name || !psz_value )
479 msg_Err( p_update->p_libvlc, "Error while parsing %s",
480 UPDATE_VLC_STATUS_URL );
486 if( strcmp( psz_eltname, "version" ) == 0 )
488 if( !strcmp( psz_name, "major" ) )
489 tmp_release.psz_major = STRDUP( psz_value );
490 else if( !strcmp( psz_name, "minor" ) )
491 tmp_release.psz_minor = STRDUP( psz_value );
492 else if( !strcmp( psz_name, "revision" ) )
493 tmp_release.psz_revision = STRDUP( psz_value );
494 else if( !strcmp( psz_name, "extra" ) )
495 tmp_release.psz_extra = STRDUP( psz_value );
496 else if( !strcmp( psz_name, "svn" ) )
497 tmp_release.psz_svn_revision =
499 else if( !strcmp( psz_name, "version" ) )
501 if( !strcmp( psz_value, "unstable" ) )
503 UPDATE_RELEASE_TYPE_UNSTABLE;
504 else if( !strcmp( psz_value, "testing" ) )
506 UPDATE_RELEASE_TYPE_TESTING;
509 UPDATE_RELEASE_TYPE_STABLE;
512 else if( !strcmp( psz_eltname, "file" ) )
514 if( !strcmp( psz_name, "type" ) )
516 if( !strcmp( psz_value, "info" ) )
517 tmp_file.i_type = UPDATE_FILE_TYPE_INFO;
518 else if( !strcmp( psz_value, "source" ) )
519 tmp_file.i_type = UPDATE_FILE_TYPE_SOURCE;
520 else if( !strcmp( psz_value, "binary" ) )
521 tmp_file.i_type = UPDATE_FILE_TYPE_BINARY;
522 else if( !strcmp( psz_value, "plugin" ) )
523 tmp_file.i_type = UPDATE_FILE_TYPE_PLUGIN;
525 tmp_file.i_type = UPDATE_FILE_TYPE_UNDEF;
527 else if( !strcmp( psz_name, "md5" ) )
528 tmp_file.psz_md5 = STRDUP( psz_value );
529 else if( !strcmp( psz_name, "size" ) )
530 tmp_file.l_size = atol( psz_value );
531 else if( !strcmp( psz_name, "url" ) )
532 tmp_file.psz_url = STRDUP( psz_value );
535 if( !strcmp( psz_name, "name" )
536 && ( !strcmp( psz_value, UPDATE_VLC_OS )
537 || !strcmp( psz_value, "*" ) )
538 && !strcmp( psz_eltname, "os" ) )
542 if( b_os && !strcmp( psz_name, "name" )
543 && ( !strcmp( psz_value, UPDATE_VLC_ARCH )
544 || !strcmp( psz_value, "*" ) )
545 && !strcmp( psz_eltname, "arch" ) )
549 FREENULL( psz_name );
550 FREENULL( psz_value );
552 if( ( b_os && b_arch && strcmp( psz_eltname, "arch" ) ) )
554 if( !strcmp( psz_eltname, "version" ) )
557 /* look for a previous occurrence of this release */
558 for( i = 0; i < p_update->i_releases; i++ )
560 p_release = p_update->p_releases + i;
561 if( CompareReleases( p_release, &tmp_release )
562 == UPDATE_RELEASE_STATUS_EQUAL )
567 /* if this is the first time that we see this release,
568 * append it to the list of releases */
569 if( i == p_update->i_releases )
571 tmp_release.i_status =
572 CompareReleaseToCurrent( &tmp_release );
573 p_update->p_releases =
574 (struct update_release_t *)realloc( p_update->p_releases,
575 (++(p_update->i_releases))*sizeof( struct update_release_t ) );
576 p_update->p_releases[ p_update->i_releases - 1 ] =
579 p_update->p_releases + p_update->i_releases - 1;
580 tmp_release.psz_major = NULL;
581 tmp_release.psz_minor = NULL;
582 tmp_release.psz_revision = NULL;
583 tmp_release.psz_extra = NULL;
584 tmp_release.psz_svn_revision = NULL;
585 tmp_release.i_type = UPDATE_RELEASE_TYPE_STABLE;
586 tmp_release.i_status = 0;
587 tmp_release.p_files = NULL;
588 tmp_release.i_files = 0;
592 FREENULL( tmp_release.psz_major );
593 FREENULL( tmp_release.psz_minor );
594 FREENULL( tmp_release.psz_revision );
595 FREENULL( tmp_release.psz_extra );
596 FREENULL( tmp_release.psz_svn_revision );
597 tmp_release.i_type = UPDATE_RELEASE_TYPE_STABLE;
598 FREENULL( tmp_release.p_files );
599 tmp_release.i_files = 0;
602 else if( !strcmp( psz_eltname, "file" ) )
604 /* append file to p_release's file list */
605 if( p_release == NULL )
610 (struct update_file_t *)realloc( p_release->p_files,
611 (++(p_release->i_files))*sizeof( struct update_file_t ) );
612 p_release->p_files[ p_release->i_files - 1 ] = tmp_file;
613 tmp_file.i_type = UPDATE_FILE_TYPE_UNDEF;
614 tmp_file.psz_md5 = NULL;
616 tmp_file.psz_url = NULL;
617 tmp_file.psz_description = NULL;
620 FREENULL( psz_eltname );
623 case XML_READER_ENDELEM:
624 psz_eltname = xml_ReaderName( p_xml_reader );
627 msg_Err( p_update->p_libvlc, "Error while parsing %s",
628 UPDATE_VLC_STATUS_URL );
632 if( !strcmp( psz_eltname, "os" ) )
634 else if( !strcmp( psz_eltname, "arch" ) )
636 FREENULL( psz_eltname );
639 case XML_READER_TEXT:
640 psz_eltvalue = xml_ReaderValue( p_xml_reader );
641 if( p_release && p_release->i_files )
642 p_release->p_files[ p_release->i_files - 1 ]
643 .psz_description = STRDUP( psz_eltvalue );
644 FREENULL( psz_eltvalue );
649 p_update->b_releases = VLC_TRUE;
652 vlc_mutex_unlock( &p_update->lock );
655 free( psz_eltvalue );
659 free( tmp_release.psz_major );
660 free( tmp_release.psz_minor );
661 free( tmp_release.psz_revision );
662 free( tmp_release.psz_extra );
663 free( tmp_release.psz_svn_revision );
665 free( tmp_file.psz_md5 );
666 free( tmp_file.psz_url );
667 free( tmp_file.psz_description );
669 if( p_xml_reader && p_xml )
670 xml_ReaderDelete( p_xml, p_xml_reader );
672 stream_Delete( p_stream );
680 * \param p_update pointer to update struct
681 * \param b_force set to VLC_TRUE if you want to force the update
684 void update_Check( update_t *p_update, vlc_bool_t b_force )
686 if( p_update == NULL ) return;
687 GetMirrorsList( p_update, b_force );
688 GetFilesList( p_update, b_force );
692 * Compare two release numbers
693 * The comparision algorith basically performs an alphabetical order (strcmp)
694 * comparision of each of the version number elements until it finds two
695 * different ones. This is the tricky function.
697 * \param p1 first release
698 * \param p2 second release
699 * \return like strcmp
701 int CompareReleases( struct update_release_t *p1, struct update_release_t *p2 )
704 if( ( d = strcmp( p1->psz_major, p2->psz_major ) ) ) ;
705 else if( ( d = strcmp( p1->psz_minor, p2->psz_minor ) ) ) ;
706 else if( ( d = strcmp( p1->psz_revision, p2->psz_revision ) ) ) ;
709 d = strcmp( p1->psz_extra, p2->psz_extra );
713 * not num < NULL < num
714 * -test and -svn releases are thus always considered older than
715 * -'' or -0 releases, which is the best i could come up with */
718 strtol( p1->psz_extra, &psz_end1, 10 );
719 strtol( p2->psz_extra, &psz_end2, 10 );
720 if( psz_end2 == p2->psz_extra
721 && ( psz_end1 != p1->psz_extra || *p1->psz_extra == '\0' ) )
726 return UPDATE_RELEASE_STATUS_OLDER;
728 return UPDATE_RELEASE_STATUS_EQUAL;
730 return UPDATE_RELEASE_STATUS_NEWER;
734 * Compare a given release's version number to the current VLC's one
737 * \return >0 if newer, 0 if equal and <0 if older
739 int CompareReleaseToCurrent( struct update_release_t *p )
741 struct update_release_t c;
744 memset( &c, 0, sizeof(struct update_release_t) );
745 c.psz_major = STRDUP( PACKAGE_VERSION_MAJOR );
746 c.psz_minor = STRDUP( PACKAGE_VERSION_MINOR );
747 c.psz_revision = STRDUP( PACKAGE_VERSION_REVISION );
748 c.psz_extra = STRDUP( PACKAGE_VERSION_EXTRA );
749 r = CompareReleases( p, &c );
752 free( c.psz_revision );
757 /*****************************************************************************
758 * Updatei_iterator_t functions
759 *****************************************************************************/
762 * Create a new update iterator structure. This structure can then be used to
763 * describe a position and move through the update and mirror trees/lists.
764 * This will use an existing update struct or create a new one if none is
767 * \param p_u the calling update_t
768 * \return a pointer to an update iterator
770 update_iterator_t *update_iterator_New( update_t *p_u )
772 update_iterator_t *p_uit = NULL;
777 p_uit = (update_iterator_t *)malloc( sizeof( update_iterator_t ) );
778 if( p_uit == NULL ) return NULL;
786 p_uit->i_t = UPDATE_FILE_TYPE_ALL;
787 p_uit->i_rs = UPDATE_RELEASE_STATUS_ALL;
788 p_uit->i_rt = UPDATE_RELEASE_TYPE_STABLE;
790 p_uit->file.i_type = UPDATE_FILE_TYPE_NONE;
791 p_uit->file.psz_md5 = NULL;
792 p_uit->file.psz_url = NULL;
793 p_uit->file.l_size = 0;
794 p_uit->file.psz_description = NULL;
796 p_uit->release.psz_version = NULL;
797 p_uit->release.psz_svn_revision = NULL;
798 p_uit->release.i_type = UPDATE_RELEASE_TYPE_UNSTABLE;
799 p_uit->release.i_status = UPDATE_RELEASE_STATUS_NONE;
801 p_uit->mirror.psz_name = NULL;
802 p_uit->mirror.psz_location = NULL;
803 p_uit->mirror.psz_type = NULL;
809 * Delete an update iterator structure (duh!)
811 * \param p_uit pointer to an update iterator
814 void update_iterator_Delete( update_iterator_t *p_uit )
817 update_iterator_ClearData( p_uit );
822 * Reset an update_iterator_t structure
824 * \param p_uit pointer to an update iterator
825 * \return UPDATE_FAIL upon error, UPDATE_SUCCESS otherwise
827 unsigned int update_iterator_Reset( update_iterator_t *p_uit )
829 if( !p_uit ) return UPDATE_FAIL;
835 update_iterator_ClearData( p_uit );
836 return UPDATE_SUCCESS;
840 * Finds the next file in the update tree that matches status and type
841 * requirements set in the update_iterator
843 * \param p_uit update iterator
844 * \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
846 unsigned int update_iterator_NextFile( update_iterator_t *p_uit )
850 if( !p_uit ) return UPDATE_FAIL;
854 /* if the update iterator was already in a "no match" state, start over */
855 if( p_uit->i_r == -1 ) p_uit->i_r = 0;
856 //if( p_uit->i_f == -1 ) p_uit->i_f = 0;
858 vlc_mutex_lock( &p_uit->p_u->lock );
860 for( r = p_uit->i_r; r < p_uit->p_u->i_releases; r++ )
862 if( !( p_uit->p_u->p_releases[r].i_status & p_uit->i_rs ) ) continue;
863 for( f = ( r == p_uit->i_r ? p_uit->i_f + 1 : 0 );
864 f < p_uit->p_u->p_releases[r].i_files; f++ )
866 if( p_uit->p_u->p_releases[r].p_files[f].i_type & p_uit->i_t )
868 goto done;/* "double break" */
876 r = p_uit->p_u->i_releases;
878 if( old_r == p_uit->i_r )
880 update_iterator_GetData( p_uit );
881 vlc_mutex_unlock( &p_uit->p_u->lock );
882 return UPDATE_SUCCESS|UPDATE_FILE;
884 else if( p_uit->i_r == r )
888 update_iterator_GetData( p_uit );
889 vlc_mutex_unlock( &p_uit->p_u->lock );
894 update_iterator_GetData( p_uit );
895 vlc_mutex_unlock( &p_uit->p_u->lock );
896 return UPDATE_SUCCESS|UPDATE_RELEASE|UPDATE_FILE;
901 * Finds the previous file in the update tree that matches status and type
902 * requirements set in the update_iterator
904 * \param p_uit update iterator
905 * \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
908 unsigned int update_iterator_PrevFile( update_iterator_t *p_uit )
912 if( !p_uit ) return UPDATE_FAIL;
916 /* if the update iterator was already in a "no match" state, start over
917 * (begin at the end of the list) */
918 if( p_uit->i_r == -1 ) p_uit->i_r = p_uit->p_u->i_releases - 1;
919 p_uit->i_f = p_uit->p_u->p_releases[p_uit->i_r].i_files + 1;
921 vlc_mutex_lock( &p_uit->p_u->lock );
923 for( r = p_uit->i_r; r >= 0; r-- )
925 if( !( p_uit->p_u->p_releases[r].i_status & p_uit->i_rs ) ) continue;
926 for( f =( r==p_uit->i_r ? p_uit->i_f - 1 : p_uit->p_u->p_releases[r].i_files );
929 if( p_uit->p_u->p_releases[r].p_files[f].i_type & p_uit->i_t )
931 goto done;/* "double break" */
939 r = p_uit->p_u->i_releases;
941 if( old_r == p_uit->i_r )
943 update_iterator_GetData( p_uit );
944 vlc_mutex_unlock( &p_uit->p_u->lock );
945 return UPDATE_SUCCESS|UPDATE_FILE;
947 else if( p_uit->i_r == -1 )
951 update_iterator_GetData( p_uit );
952 vlc_mutex_unlock( &p_uit->p_u->lock );
957 update_iterator_GetData( p_uit );
958 vlc_mutex_unlock( &p_uit->p_u->lock );
959 return UPDATE_SUCCESS|UPDATE_RELEASE|UPDATE_FILE;
964 * Finds the next mirror in the update tree
966 * \param update iterator
967 * \return UPDATE_FAIL if we can't find the next mirror, UPDATE_SUCCESS|UPDATE_MIRROR otherwise
969 unsigned int update_iterator_NextMirror( update_iterator_t *p_uit )
971 if( !p_uit ) return UPDATE_FAIL;
972 vlc_mutex_lock( &p_uit->p_u->lock );
974 if( p_uit->i_m >= p_uit->p_u->i_mirrors ) p_uit->i_m = -1;
975 update_iterator_GetData( p_uit );
976 vlc_mutex_unlock( &p_uit->p_u->lock );
977 return p_uit->i_m == -1 ? UPDATE_FAIL : UPDATE_SUCCESS|UPDATE_MIRROR;
981 * Finds the previous mirror in the update tree
983 * \param update iterator
984 * \return UPDATE_FAIL if we can't find a previous mirror, UPDATE_SUCCESS|UPDATE_MIRROR otherwise
986 unsigned int update_iterator_PrevMirror( update_iterator_t *p_uit )
988 if( !p_uit ) return UPDATE_FAIL;
989 vlc_mutex_lock( &p_uit->p_u->lock );
991 update_iterator_GetData( p_uit );
992 vlc_mutex_unlock( &p_uit->p_u->lock );
993 return p_uit->i_m == -1 ? UPDATE_FAIL : UPDATE_SUCCESS|UPDATE_MIRROR;
997 * Change the update iterator's position in the file and mirrors tree
998 * If position is negative, don't change it
1000 * \param i_m position in mirrors list
1001 * \param i_r position in releases list
1002 * \param i_f position in release's files list
1003 * \return UPDATE_FAIL when changing position fails or position wasn't changed, a combination of UPDATE_MIRROR, UPDATE_RELEASE and UPDATE_FILE otherwise
1005 unsigned int update_iterator_ChooseMirrorAndFile( update_iterator_t *p_uit,
1006 int i_m, int i_r, int i_f )
1008 unsigned int i_val = 0;
1010 if( !p_uit ) return 0;
1011 vlc_mutex_lock( &p_uit->p_u->lock );
1015 if( i_m < p_uit->p_u->i_mirrors )
1017 if( i_m != p_uit->i_m )
1018 i_val |= UPDATE_MIRROR;
1026 if( i_r < p_uit->p_u->i_releases )
1028 if( i_r != p_uit->i_r )
1029 i_val |= UPDATE_FILE;
1037 if( i_r >= 0 && i_r < p_uit->p_u->i_releases
1038 && i_f < p_uit->p_u->p_releases[p_uit->i_r].i_files )
1040 if( i_f != p_uit->i_f )
1041 i_val |= UPDATE_FILE;
1047 update_iterator_GetData( p_uit );
1048 vlc_mutex_unlock( &p_uit->p_u->lock );
1050 if( ( i_m < 0 || p_uit->i_m >= 0 )
1051 && ( i_r < 0 || p_uit->i_r >= 0 )
1052 && ( i_f < 0 || p_uit->i_f >= 0 ) )
1054 /* Everything worked */
1055 return UPDATE_SUCCESS|i_val;
1059 /* Something failed */
1065 * Fills the iterator data (file, release and mirror structs)
1066 * The update struct should be locked before calling this function.
1068 * \param p_uit update iterator
1071 void update_iterator_GetData( update_iterator_t *p_uit )
1073 struct update_release_t *p_r = NULL;
1074 struct update_file_t *p_f = NULL;
1075 struct update_mirror_t *p_m = NULL;
1077 update_iterator_ClearData( p_uit );
1079 if( p_uit->i_m >= 0 )
1081 p_m = p_uit->p_u->p_mirrors + p_uit->i_m;
1082 p_uit->mirror.psz_name = STRDUP( p_m->psz_name );
1083 p_uit->mirror.psz_location = STRDUP( p_m->psz_location );
1084 p_uit->mirror.psz_type = STRDUP( p_m->psz_type );
1087 if( p_uit->i_r >= 0 )
1089 p_r = p_uit->p_u->p_releases + p_uit->i_r;
1090 asprintf( &p_uit->release.psz_version, "%s.%s.%s-%s",
1095 p_uit->release.psz_svn_revision = STRDUP( p_r->psz_svn_revision );
1096 p_uit->release.i_type = p_r->i_type;
1097 p_uit->release.i_status = p_r->i_status;
1098 if( p_uit->i_f >= 0 )
1100 p_f = p_r->p_files + p_uit->i_f;
1101 p_uit->file.i_type = p_f->i_type;
1102 p_uit->file.psz_md5 = STRDUP( p_f->psz_md5 );
1103 p_uit->file.l_size = p_f->l_size;
1104 p_uit->file.psz_description = STRDUP( p_f->psz_description);
1105 if( p_f->psz_url[0] == '/' )
1109 asprintf( &p_uit->file.psz_url, "%s%s",
1110 p_m->psz_base_url, p_f->psz_url );
1115 p_uit->file.psz_url = STRDUP( p_f->psz_url );
1122 * Clears the iterator data (file, release and mirror structs)
1124 * \param p_uit update iterator
1127 void update_iterator_ClearData( update_iterator_t *p_uit )
1129 p_uit->file.i_type = UPDATE_FILE_TYPE_NONE;
1130 FREENULL( p_uit->file.psz_md5 );
1131 p_uit->file.l_size = 0;
1132 FREENULL( p_uit->file.psz_description );
1133 FREENULL( p_uit->file.psz_url );
1134 FREENULL( p_uit->release.psz_version );
1135 FREENULL( p_uit->release.psz_svn_revision );
1136 p_uit->release.i_type = UPDATE_RELEASE_TYPE_UNSTABLE;
1137 p_uit->release.i_status = UPDATE_RELEASE_STATUS_NONE;
1138 FREENULL( p_uit->mirror.psz_name );
1139 FREENULL( p_uit->mirror.psz_location );
1140 FREENULL( p_uit->mirror.psz_type );
1144 * Perform an action on the update iterator
1145 * Only the first matching action is performed.
1147 * \param p_uit update iterator
1148 * \param i_action update action bitmask. can be a combination of UPDATE_NEXT, UPDATE_PREV, UPDATE_MIRROR, UPDATE_RELEASE, UPDATE_FILE, UPDATE_RESET
1149 * \return UPDATE_FAIL if action fails, UPDATE_SUCCESS|(combination of UPDATE_MIRROR, UPDATE_RELEASE and UPDATE_FILE if these changed) otherwise
1151 unsigned int update_iterator_Action( update_iterator_t *p_uit, int i_action )
1153 if( i_action & UPDATE_RESET )
1155 return update_iterator_Reset( p_uit );
1158 if( i_action & UPDATE_MIRROR )
1160 if( i_action & UPDATE_PREV )
1162 return update_iterator_PrevMirror( p_uit );
1166 return update_iterator_NextMirror( p_uit );
1169 /*else if( i_action & UPDATE_RELEASE )
1171 if( i_action & UPDATE_PREV )
1173 return update_iterator_PrevRelease( p_uit );
1177 return update_iterator_NextRelease( p_uit );
1180 else if( i_action & UPDATE_FILE )
1182 if( i_action & UPDATE_PREV )
1184 return update_iterator_PrevFile( p_uit );
1188 return update_iterator_NextFile( p_uit );
1193 return UPDATE_SUCCESS;
1198 * Object to launch download thread in a different object
1202 char *psz_dest; //< Download destination
1203 char *psz_src; //< Download source
1204 char *psz_status; //< Download status displayed in progress dialog
1205 } download_thread_t;
1207 void update_download_for_real( download_thread_t *p_this );
1210 * Download the file selected by the update iterator. This function will
1211 * launch the download in a new thread (downloads can be long)
1213 * \param p_uit update iterator
1214 * \param psz_dest destination file path
1217 void update_download( update_iterator_t *p_uit, const char *psz_dest )
1219 download_thread_t *p_dt =
1220 vlc_object_create( p_uit->p_u->p_libvlc, sizeof( download_thread_t ) );
1222 p_dt->psz_dest = strdup( psz_dest );
1223 p_dt->psz_src = strdup( p_uit->file.psz_url );
1224 asprintf( &p_dt->psz_status, "%s - %s (%s)\nSource: %s\nDestination: %s",
1225 p_uit->file.psz_description, p_uit->release.psz_version,
1226 p_uit->release.psz_svn_revision, p_uit->file.psz_url,
1229 vlc_thread_create( p_dt, "download thread", update_download_for_real,
1230 VLC_THREAD_PRIORITY_LOW, VLC_FALSE );
1234 * Convert a long int size in bytes to a string
1236 * \param l_size the size in bytes
1237 * \return the size as a string
1239 static char *size_str( long int l_size )
1243 asprintf( &psz_tmp, "%.1f GB", (float)l_size/(1<<30) );
1245 asprintf( &psz_tmp, "%.1f MB", (float)l_size/(1<<20) );
1246 else if( l_size >> 10 )
1247 asprintf( &psz_tmp, "%.1f kB", (float)l_size/(1<<10) );
1249 asprintf( &psz_tmp, "%ld B", l_size );
1254 * The true download function.
1256 * \param p_this the download_thread_t object
1259 void update_download_for_real( download_thread_t *p_this )
1261 char *psz_dest = p_this->psz_dest;
1262 char *psz_src = p_this->psz_src;
1264 libvlc_int_t *p_libvlc = p_this->p_libvlc;
1266 FILE *p_file = NULL;
1272 long int l_size, l_done = 0;
1274 vlc_thread_ready( p_this );
1276 asprintf( &psz_status, "%s\nDownloading... 0.0/? %.1f%% done",
1277 p_this->psz_status, 0.0 );
1278 i_progress = intf_UserProgress( p_libvlc, "Downloading...",
1279 psz_status, 0.0, 0 );
1281 p_stream = stream_UrlNew( p_libvlc, psz_src );
1284 msg_Err( p_libvlc, "Failed to open %s for reading", psz_src );
1285 intf_UserFatal( p_libvlc, VLC_TRUE, "Error while Downloading...",
1286 "VLC failed to open %s for reading.", psz_src );
1287 intf_UserHide( p_libvlc, i_progress );
1292 p_file = utf8_fopen( psz_dest, "w" );
1295 msg_Err( p_libvlc, "Failed to open %s for writing", psz_dest );
1296 intf_UserFatal( p_libvlc, VLC_TRUE, "Error while Downloading...",
1297 "VLC failed to open %s for writing.", psz_dest );
1298 intf_UserHide( p_libvlc, i_progress );
1303 char *psz_s1; char *psz_s2;
1305 l_size = stream_Size(p_stream);
1306 p_buffer = (void *)malloc( 1<<10 );
1308 while( ( l_read = stream_Read( p_stream, p_buffer, 1<<10 ) ) )
1312 fwrite( p_buffer, l_read, 1, p_file );
1316 f_progress = 100.0*(float)l_done/(float)l_size;
1317 psz_s1 = size_str( l_done );
1318 psz_s2 = size_str( l_size );
1319 asprintf( &psz_status, "%s\nDownloading... %s/%s (%.1f%%) done",
1320 p_this->psz_status, psz_s1, psz_s2, f_progress );
1321 free( psz_s1 ); free( psz_s2 );
1323 intf_ProgressUpdate( p_libvlc, i_progress,
1324 psz_status, f_progress, 0 );
1329 stream_Delete( p_stream );
1332 psz_s2 = size_str( l_size );
1333 asprintf( &psz_status, "%s\nDone %s (100.00%%)",
1334 p_this->psz_status, psz_s2 );
1336 intf_ProgressUpdate( p_libvlc, i_progress, psz_status, 100.0, 0 );
1341 free( p_this->psz_dest );
1342 free( p_this->psz_src );
1343 free( p_this->psz_status );
1345 vlc_object_destroy( p_this );