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 *****************************************************************************/
41 #include <stdlib.h> /* malloc(), free() */
42 #include <ctype.h> /* tolower() */
45 #include "vlc_update.h"
47 #include "vlc_block.h"
48 #include "vlc_stream.h"
50 #include "vlc_interaction.h"
53 /*****************************************************************************
55 *****************************************************************************/
57 /* All release notes and source packages should match on "*"
58 * Only binary installers are OS specific ( we only provide these
59 * for Win32, Mac OS X, WincCE, beos(?) ) */
60 #if defined( UNDER_CE )
61 # define UPDATE_VLC_OS "*"
62 # define UPDATE_VLC_ARCH "*"
63 #elif defined( WIN32 )
64 # define UPDATE_VLC_OS "windows"
65 # define UPDATE_VLC_ARCH "i386"
66 #elif defined( __APPLE__ )
67 # define UPDATE_VLC_OS "macosx"
68 # if defined( __powerpc__ ) || defined( __ppc__ ) || defined( __ppc64__ )
69 # define UPDATE_VLC_ARCH "ppc"
71 # define UPDATE_VLC_ARCH "x86"
73 #elif defined( SYS_BEOS )
74 # define UPDATE_VLC_OS "beos"
75 # define UPDATE_VLC_ARCH "i386"
77 # define UPDATE_VLC_OS "*"
78 # define UPDATE_VLC_ARCH "*"
81 #define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status.xml"
82 #define UPDATE_VLC_MIRRORS_URL "http://update.videolan.org/mirrors.xml"
84 #define STRDUP( a ) ( a ? strdup( a ) : NULL )
86 /*****************************************************************************
88 *****************************************************************************/
90 void FreeMirrorsList( update_t * );
91 void FreeReleasesList( update_t * );
92 void GetMirrorsList( update_t *, vlc_bool_t );
93 void GetFilesList( update_t *, vlc_bool_t );
95 int CompareReleases( struct update_release_t *, struct update_release_t * );
96 int CompareReleaseToCurrent( struct update_release_t * );
98 unsigned int update_iterator_Reset( update_iterator_t * );
99 unsigned int update_iterator_NextFile( update_iterator_t * );
100 unsigned int update_iterator_PrevFile( update_iterator_t * );
101 unsigned int update_iterator_NextMirror( update_iterator_t * );
102 unsigned int update_iterator_PrevMirror( update_iterator_t * );
104 void update_iterator_GetData( update_iterator_t * );
105 void update_iterator_ClearData( update_iterator_t * );
107 /*****************************************************************************
109 *****************************************************************************/
112 * Create a new update VLC struct
114 * \param p_this the calling vlc_object
115 * \return pointer to new update_t or NULL
117 update_t *__update_New( vlc_object_t *p_this )
121 if( p_this == NULL ) return NULL;
123 p_update = (update_t *)malloc( sizeof( update_t ) );
125 vlc_mutex_init( p_this, &p_update->lock );
127 p_update->p_libvlc = p_this->p_libvlc;
129 p_update->p_releases = NULL;
130 p_update->i_releases = 0;
131 p_update->b_releases = VLC_FALSE;
133 p_update->p_mirrors = NULL;
134 p_update->i_mirrors = 0;
135 p_update->b_mirrors = VLC_FALSE;
141 * Delete an update_t struct
143 * \param p_update update_t* pointer
146 void update_Delete( update_t *p_update )
148 vlc_mutex_destroy( &p_update->lock );
149 FreeMirrorsList( p_update );
150 FreeReleasesList( p_update );
155 * Empty the mirrors list
156 * *p_update should be locked before using this function
158 * \param p_update pointer to the update struct
161 void FreeMirrorsList( update_t *p_update )
165 for( i = 0; i < p_update->i_mirrors; i++ )
167 free( p_update->p_mirrors[i].psz_name );
168 free( p_update->p_mirrors[i].psz_location );
169 free( p_update->p_mirrors[i].psz_type );
170 free( p_update->p_mirrors[i].psz_base_url );
172 FREENULL( p_update->p_mirrors );
173 p_update->i_mirrors = 0;
174 p_update->b_mirrors = VLC_FALSE;
178 * Empty the releases list
179 * *p_update should be locked before calling this function
181 * \param p_update pointer to the update struct
184 void FreeReleasesList( update_t *p_update )
188 for( i = 0; i < p_update->i_releases; i++ )
191 struct update_release_t *p_release = (p_update->p_releases + i);
192 for( j = 0; j < p_release->i_files; j++ )
194 free( p_release->p_files[j].psz_md5 );
195 free( p_release->p_files[j].psz_url );
196 free( p_release->p_files[j].psz_description );
198 free( p_release->psz_major );
199 free( p_release->psz_minor );
200 free( p_release->psz_revision );
201 free( p_release->psz_extra );
202 free( p_release->psz_svn_revision );
203 free( p_release->p_files );
205 FREENULL( p_update->p_releases );
206 p_update->i_releases = 0;
207 p_update->b_releases = VLC_FALSE;
211 * Get the mirrors list XML file and parse it
212 * *p_update has to be unlocked when calling this function
214 * \param p_update pointer to the update struct
215 * \param b_force set to VLC_TRUE if you want to force the mirrors list update
218 void GetMirrorsList( update_t *p_update, vlc_bool_t b_force )
220 stream_t *p_stream = NULL;
223 xml_reader_t *p_xml_reader = NULL;
224 char *psz_eltname = NULL;
225 //char *psz_eltvalue = NULL;
226 char *psz_name = NULL;
227 char *psz_value = NULL;
228 struct update_mirror_t tmp_mirror;
230 vlc_mutex_lock( &p_update->lock );
232 memset( &tmp_mirror, 0, sizeof(struct update_mirror_t));
234 if( p_update->b_mirrors && b_force == VLC_FALSE )
236 vlc_mutex_unlock( &p_update->lock );
240 p_xml = xml_Create( p_update->p_libvlc );
243 msg_Err( p_update->p_libvlc, "Failed to open XML parser" );
247 p_stream = stream_UrlNew( p_update->p_libvlc, UPDATE_VLC_MIRRORS_URL );
250 msg_Err( p_update->p_libvlc, "Failed to open %s for reading",
251 UPDATE_VLC_MIRRORS_URL );
255 p_xml_reader = xml_ReaderCreate( p_xml, p_stream );
259 msg_Err( p_update->p_libvlc, "Failed to open %s for parsing",
260 UPDATE_VLC_MIRRORS_URL );
264 if( p_update->p_mirrors )
266 FreeMirrorsList( p_update );
269 while( xml_ReaderRead( p_xml_reader ) == 1 )
271 switch( xml_ReaderNodeType( p_xml_reader ) )
274 msg_Err( p_update->p_libvlc, "Error while parsing %s",
275 UPDATE_VLC_MIRRORS_URL );
278 case XML_READER_STARTELEM:
279 psz_eltname = xml_ReaderName( p_xml_reader );
282 msg_Err( p_update->p_libvlc, "Error while parsing %s",
283 UPDATE_VLC_MIRRORS_URL );
287 while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
289 psz_name = xml_ReaderName( p_xml_reader );
290 psz_value = xml_ReaderValue( p_xml_reader );
292 if( !psz_name || !psz_value )
294 msg_Err( p_update->p_libvlc, "Error while parsing %s",
295 UPDATE_VLC_MIRRORS_URL );
299 if( !strcmp( psz_eltname, "mirror" ) )
301 if( !strcmp( psz_name, "name" ) )
302 tmp_mirror.psz_name = STRDUP( psz_value );
303 else if( !strcmp( psz_name, "location" ) )
304 tmp_mirror.psz_location = STRDUP( psz_value );
306 else if( !strcmp( psz_eltname, "url" ) )
308 if( !strcmp( psz_name, "type" ) )
309 tmp_mirror.psz_type = STRDUP( psz_value );
310 else if( !strcmp( psz_name, "base" ) )
311 tmp_mirror.psz_base_url = STRDUP( psz_value );
313 FREENULL( psz_name );
314 FREENULL( psz_value );
316 if( !strcmp( psz_eltname, "url" ) )
318 /* append to mirrors list */
319 p_update->p_mirrors =
320 (struct update_mirror_t *)realloc( p_update->p_mirrors,
321 (++(p_update->i_mirrors))
322 *sizeof( struct update_mirror_t ) );
323 p_update->p_mirrors[ p_update->i_mirrors - 1 ] =
325 tmp_mirror.psz_name = STRDUP( tmp_mirror.psz_name );
326 tmp_mirror.psz_location = STRDUP( tmp_mirror.psz_location );
327 tmp_mirror.psz_type = NULL;
328 tmp_mirror.psz_base_url = NULL;
330 FREENULL( psz_eltname );
333 case XML_READER_ENDELEM:
334 psz_eltname = xml_ReaderName( p_xml_reader );
337 msg_Err( p_update->p_libvlc, "Error while parsing %s",
338 UPDATE_VLC_MIRRORS_URL );
342 if( !strcmp( psz_eltname, "mirror" ) )
344 FREENULL( tmp_mirror.psz_name );
345 FREENULL( tmp_mirror.psz_location );
348 FREENULL( psz_eltname );
351 /*case XML_READER_TEXT:
352 psz_eltvalue = xml_ReaderValue( p_xml_reader );
353 FREENULL( psz_eltvalue );
358 p_update->b_mirrors = VLC_TRUE;
361 vlc_mutex_unlock( &p_update->lock );
364 //free( psz_eltvalue );
368 free( tmp_mirror.psz_name );
369 free( tmp_mirror.psz_location );
370 free( tmp_mirror.psz_type );
371 free( tmp_mirror.psz_base_url );
373 if( p_xml_reader && p_xml )
374 xml_ReaderDelete( p_xml, p_xml_reader );
376 stream_Delete( p_stream );
382 * Get the files list XML file and parse it
383 * *p_update has to be unlocked when calling this function
385 * \param p_update pointer to update struct
386 * \param b_force set to VLC_TRUE if you want to force the files list update
389 void GetFilesList( update_t *p_update, vlc_bool_t b_force )
391 stream_t *p_stream = NULL;
394 xml_reader_t *p_xml_reader = NULL;
396 char *psz_eltname = NULL;
397 char *psz_eltvalue = NULL;
398 char *psz_name = NULL;
399 char *psz_value = NULL;
401 struct update_release_t *p_release = NULL;
402 struct update_release_t tmp_release;
403 struct update_file_t tmp_file;
405 vlc_bool_t b_os = VLC_FALSE, b_arch = VLC_FALSE;
407 memset( &tmp_release, 0, sizeof(struct update_release_t) );
408 memset( &tmp_file, 0, sizeof(struct update_file_t) );
410 tmp_release.i_type = UPDATE_RELEASE_TYPE_STABLE;
412 vlc_mutex_lock( &p_update->lock );
414 if( p_update->b_releases && b_force == VLC_FALSE )
416 vlc_mutex_unlock( &p_update->lock );
420 p_xml = xml_Create( p_update->p_libvlc );
423 msg_Err( p_update->p_libvlc, "Failed to open XML parser" );
427 p_stream = stream_UrlNew( p_update->p_libvlc, UPDATE_VLC_STATUS_URL );
430 msg_Err( p_update->p_libvlc, "Failed to open %s for reading",
431 UPDATE_VLC_STATUS_URL );
435 p_xml_reader = xml_ReaderCreate( p_xml, p_stream );
439 msg_Err( p_update->p_libvlc, "Failed to open %s for parsing",
440 UPDATE_VLC_STATUS_URL );
444 if( p_update->p_releases )
446 FreeReleasesList( p_update );
449 while( xml_ReaderRead( p_xml_reader ) == 1 )
451 switch( xml_ReaderNodeType( p_xml_reader ) )
454 msg_Err( p_update->p_libvlc, "Error while parsing %s",
455 UPDATE_VLC_STATUS_URL );
458 case XML_READER_STARTELEM:
459 psz_eltname = xml_ReaderName( p_xml_reader );
462 msg_Err( p_update->p_libvlc, "Error while parsing %s",
463 UPDATE_VLC_STATUS_URL );
467 while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
469 psz_name = xml_ReaderName( p_xml_reader );
470 psz_value = xml_ReaderValue( p_xml_reader );
472 if( !psz_name || !psz_value )
474 msg_Err( p_update->p_libvlc, "Error while parsing %s",
475 UPDATE_VLC_STATUS_URL );
481 if( strcmp( psz_eltname, "version" ) == 0 )
483 if( !strcmp( psz_name, "major" ) )
484 tmp_release.psz_major = STRDUP( psz_value );
485 else if( !strcmp( psz_name, "minor" ) )
486 tmp_release.psz_minor = STRDUP( psz_value );
487 else if( !strcmp( psz_name, "revision" ) )
488 tmp_release.psz_revision = STRDUP( psz_value );
489 else if( !strcmp( psz_name, "extra" ) )
490 tmp_release.psz_extra = STRDUP( psz_value );
491 else if( !strcmp( psz_name, "svn" ) )
492 tmp_release.psz_svn_revision =
494 else if( !strcmp( psz_name, "version" ) )
496 if( !strcmp( psz_value, "unstable" ) )
498 UPDATE_RELEASE_TYPE_UNSTABLE;
499 else if( !strcmp( psz_value, "testing" ) )
501 UPDATE_RELEASE_TYPE_TESTING;
504 UPDATE_RELEASE_TYPE_STABLE;
507 else if( !strcmp( psz_eltname, "file" ) )
509 if( !strcmp( psz_name, "type" ) )
511 if( !strcmp( psz_value, "info" ) )
512 tmp_file.i_type = UPDATE_FILE_TYPE_INFO;
513 else if( !strcmp( psz_value, "source" ) )
514 tmp_file.i_type = UPDATE_FILE_TYPE_SOURCE;
515 else if( !strcmp( psz_value, "binary" ) )
516 tmp_file.i_type = UPDATE_FILE_TYPE_BINARY;
517 else if( !strcmp( psz_value, "plugin" ) )
518 tmp_file.i_type = UPDATE_FILE_TYPE_PLUGIN;
520 tmp_file.i_type = UPDATE_FILE_TYPE_UNDEF;
522 else if( !strcmp( psz_name, "md5" ) )
523 tmp_file.psz_md5 = STRDUP( psz_value );
524 else if( !strcmp( psz_name, "size" ) )
525 tmp_file.l_size = atol( psz_value );
526 else if( !strcmp( psz_name, "url" ) )
527 tmp_file.psz_url = STRDUP( psz_value );
530 if( !strcmp( psz_name, "name" )
531 && ( !strcmp( psz_value, UPDATE_VLC_OS )
532 || !strcmp( psz_value, "*" ) )
533 && !strcmp( psz_eltname, "os" ) )
537 if( b_os && !strcmp( psz_name, "name" )
538 && ( !strcmp( psz_value, UPDATE_VLC_ARCH )
539 || !strcmp( psz_value, "*" ) )
540 && !strcmp( psz_eltname, "arch" ) )
544 FREENULL( psz_name );
545 FREENULL( psz_value );
547 if( ( b_os && b_arch && strcmp( psz_eltname, "arch" ) ) )
549 if( !strcmp( psz_eltname, "version" ) )
552 /* look for a previous occurrence of this release */
553 for( i = 0; i < p_update->i_releases; i++ )
555 p_release = p_update->p_releases + i;
556 if( CompareReleases( p_release, &tmp_release )
557 == UPDATE_RELEASE_STATUS_EQUAL )
562 /* if this is the first time that we see this release,
563 * append it to the list of releases */
564 if( i == p_update->i_releases )
566 tmp_release.i_status =
567 CompareReleaseToCurrent( &tmp_release );
568 p_update->p_releases =
569 (struct update_release_t *)realloc( p_update->p_releases,
570 (++(p_update->i_releases))*sizeof( struct update_release_t ) );
571 p_update->p_releases[ p_update->i_releases - 1 ] =
574 p_update->p_releases + p_update->i_releases - 1;
575 tmp_release.psz_major = NULL;
576 tmp_release.psz_minor = NULL;
577 tmp_release.psz_revision = NULL;
578 tmp_release.psz_extra = NULL;
579 tmp_release.psz_svn_revision = NULL;
580 tmp_release.i_type = UPDATE_RELEASE_TYPE_STABLE;
581 tmp_release.i_status = 0;
582 tmp_release.p_files = NULL;
583 tmp_release.i_files = 0;
587 FREENULL( tmp_release.psz_major );
588 FREENULL( tmp_release.psz_minor );
589 FREENULL( tmp_release.psz_revision );
590 FREENULL( tmp_release.psz_extra );
591 FREENULL( tmp_release.psz_svn_revision );
592 tmp_release.i_type = UPDATE_RELEASE_TYPE_STABLE;
593 FREENULL( tmp_release.p_files );
594 tmp_release.i_files = 0;
597 else if( !strcmp( psz_eltname, "file" ) )
599 /* append file to p_release's file list */
600 if( p_release == NULL )
605 (struct update_file_t *)realloc( p_release->p_files,
606 (++(p_release->i_files))*sizeof( struct update_file_t ) );
607 p_release->p_files[ p_release->i_files - 1 ] = tmp_file;
608 tmp_file.i_type = UPDATE_FILE_TYPE_UNDEF;
609 tmp_file.psz_md5 = NULL;
611 tmp_file.psz_url = NULL;
612 tmp_file.psz_description = NULL;
615 FREENULL( psz_eltname );
618 case XML_READER_ENDELEM:
619 psz_eltname = xml_ReaderName( p_xml_reader );
622 msg_Err( p_update->p_libvlc, "Error while parsing %s",
623 UPDATE_VLC_STATUS_URL );
627 if( !strcmp( psz_eltname, "os" ) )
629 else if( !strcmp( psz_eltname, "arch" ) )
631 FREENULL( psz_eltname );
634 case XML_READER_TEXT:
635 psz_eltvalue = xml_ReaderValue( p_xml_reader );
636 if( p_release && p_release->i_files )
637 p_release->p_files[ p_release->i_files - 1 ]
638 .psz_description = STRDUP( psz_eltvalue );
639 FREENULL( psz_eltvalue );
644 p_update->b_releases = VLC_TRUE;
647 vlc_mutex_unlock( &p_update->lock );
650 free( psz_eltvalue );
654 free( tmp_release.psz_major );
655 free( tmp_release.psz_minor );
656 free( tmp_release.psz_revision );
657 free( tmp_release.psz_extra );
658 free( tmp_release.psz_svn_revision );
660 free( tmp_file.psz_md5 );
661 free( tmp_file.psz_url );
662 free( tmp_file.psz_description );
664 if( p_xml_reader && p_xml )
665 xml_ReaderDelete( p_xml, p_xml_reader );
667 stream_Delete( p_stream );
675 * \param p_update pointer to update struct
676 * \param b_force set to VLC_TRUE if you want to force the update
679 void update_Check( update_t *p_update, vlc_bool_t b_force )
681 if( p_update == NULL ) return;
682 GetMirrorsList( p_update, b_force );
683 GetFilesList( p_update, b_force );
687 * Compare two release numbers
688 * The comparision algorith basically performs an alphabetical order (strcmp)
689 * comparision of each of the version number elements until it finds two
690 * different ones. This is the tricky function.
692 * \param p1 first release
693 * \param p2 second release
694 * \return like strcmp
696 int CompareReleases( struct update_release_t *p1, struct update_release_t *p2 )
699 if( ( d = strcmp( p1->psz_major, p2->psz_major ) ) ) ;
700 else if( ( d = strcmp( p1->psz_minor, p2->psz_minor ) ) ) ;
701 else if( ( d = strcmp( p1->psz_revision, p2->psz_revision ) ) ) ;
704 d = strcmp( p1->psz_extra, p2->psz_extra );
708 * not num < NULL < num
709 * -test and -svn releases are thus always considered older than
710 * -'' or -0 releases, which is the best i could come up with */
713 strtol( p1->psz_extra, &psz_end1, 10 );
714 strtol( p2->psz_extra, &psz_end2, 10 );
715 if( psz_end2 == p2->psz_extra
716 && ( psz_end1 != p1->psz_extra || *p1->psz_extra == '\0' ) )
721 return UPDATE_RELEASE_STATUS_OLDER;
723 return UPDATE_RELEASE_STATUS_EQUAL;
725 return UPDATE_RELEASE_STATUS_NEWER;
729 * Compare a given release's version number to the current VLC's one
732 * \return >0 if newer, 0 if equal and <0 if older
734 int CompareReleaseToCurrent( struct update_release_t *p )
736 struct update_release_t c;
739 memset( &c, 0, sizeof(struct update_release_t) );
740 c.psz_major = STRDUP( PACKAGE_VERSION_MAJOR );
741 c.psz_minor = STRDUP( PACKAGE_VERSION_MINOR );
742 c.psz_revision = STRDUP( PACKAGE_VERSION_REVISION );
743 c.psz_extra = STRDUP( PACKAGE_VERSION_EXTRA );
744 r = CompareReleases( p, &c );
747 free( c.psz_revision );
752 /*****************************************************************************
753 * Updatei_iterator_t functions
754 *****************************************************************************/
757 * Create a new update iterator structure. This structure can then be used to
758 * describe a position and move through the update and mirror trees/lists.
759 * This will use an existing update struct or create a new one if none is
762 * \param p_u the calling update_t
763 * \return a pointer to an update iterator
765 update_iterator_t *update_iterator_New( update_t *p_u )
767 update_iterator_t *p_uit = NULL;
772 p_uit = (update_iterator_t *)malloc( sizeof( update_iterator_t ) );
773 if( p_uit == NULL ) return NULL;
781 p_uit->i_t = UPDATE_FILE_TYPE_ALL;
782 p_uit->i_rs = UPDATE_RELEASE_STATUS_ALL;
783 p_uit->i_rt = UPDATE_RELEASE_TYPE_STABLE;
785 p_uit->file.i_type = UPDATE_FILE_TYPE_NONE;
786 p_uit->file.psz_md5 = NULL;
787 p_uit->file.psz_url = NULL;
788 p_uit->file.l_size = 0;
789 p_uit->file.psz_description = NULL;
791 p_uit->release.psz_version = NULL;
792 p_uit->release.psz_svn_revision = NULL;
793 p_uit->release.i_type = UPDATE_RELEASE_TYPE_UNSTABLE;
794 p_uit->release.i_status = UPDATE_RELEASE_STATUS_NONE;
796 p_uit->mirror.psz_name = NULL;
797 p_uit->mirror.psz_location = NULL;
798 p_uit->mirror.psz_type = NULL;
804 * Delete an update iterator structure (duh!)
806 * \param p_uit pointer to an update iterator
809 void update_iterator_Delete( update_iterator_t *p_uit )
812 update_iterator_ClearData( p_uit );
817 * Reset an update_iterator_t structure
819 * \param p_uit pointer to an update iterator
820 * \return UPDATE_FAIL upon error, UPDATE_SUCCESS otherwise
822 unsigned int update_iterator_Reset( update_iterator_t *p_uit )
824 if( !p_uit ) return UPDATE_FAIL;
830 update_iterator_ClearData( p_uit );
831 return UPDATE_SUCCESS;
835 * Finds the next file in the update tree that matches status and type
836 * requirements set in the update_iterator
838 * \param p_uit update iterator
839 * \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
841 unsigned int update_iterator_NextFile( update_iterator_t *p_uit )
845 if( !p_uit ) return UPDATE_FAIL;
849 /* if the update iterator was already in a "no match" state, start over */
850 if( p_uit->i_r == -1 ) p_uit->i_r = 0;
851 //if( p_uit->i_f == -1 ) p_uit->i_f = 0;
853 vlc_mutex_lock( &p_uit->p_u->lock );
855 for( r = p_uit->i_r; r < p_uit->p_u->i_releases; r++ )
857 if( !( p_uit->p_u->p_releases[r].i_status & p_uit->i_rs ) ) continue;
858 for( f = ( r == p_uit->i_r ? p_uit->i_f + 1 : 0 );
859 f < p_uit->p_u->p_releases[r].i_files; f++ )
861 if( p_uit->p_u->p_releases[r].p_files[f].i_type & p_uit->i_t )
863 goto done;/* "double break" */
871 r = p_uit->p_u->i_releases;
873 if( old_r == p_uit->i_r )
875 update_iterator_GetData( p_uit );
876 vlc_mutex_unlock( &p_uit->p_u->lock );
877 return UPDATE_SUCCESS|UPDATE_FILE;
879 else if( p_uit->i_r == r )
883 update_iterator_GetData( p_uit );
884 vlc_mutex_unlock( &p_uit->p_u->lock );
889 update_iterator_GetData( p_uit );
890 vlc_mutex_unlock( &p_uit->p_u->lock );
891 return UPDATE_SUCCESS|UPDATE_RELEASE|UPDATE_FILE;
896 * Finds the previous file in the update tree that matches status and type
897 * requirements set in the update_iterator
899 * \param p_uit update iterator
900 * \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
903 unsigned int update_iterator_PrevFile( update_iterator_t *p_uit )
907 if( !p_uit ) return UPDATE_FAIL;
911 /* if the update iterator was already in a "no match" state, start over
912 * (begin at the end of the list) */
913 if( p_uit->i_r == -1 ) p_uit->i_r = p_uit->p_u->i_releases - 1;
914 p_uit->i_f = p_uit->p_u->p_releases[p_uit->i_r].i_files + 1;
916 vlc_mutex_lock( &p_uit->p_u->lock );
918 for( r = p_uit->i_r; r >= 0; r-- )
920 if( !( p_uit->p_u->p_releases[r].i_status & p_uit->i_rs ) ) continue;
921 for( f =( r==p_uit->i_r ? p_uit->i_f - 1 : p_uit->p_u->p_releases[r].i_files );
924 if( p_uit->p_u->p_releases[r].p_files[f].i_type & p_uit->i_t )
926 goto done;/* "double break" */
934 r = p_uit->p_u->i_releases;
936 if( old_r == p_uit->i_r )
938 update_iterator_GetData( p_uit );
939 vlc_mutex_unlock( &p_uit->p_u->lock );
940 return UPDATE_SUCCESS|UPDATE_FILE;
942 else if( p_uit->i_r == -1 )
946 update_iterator_GetData( p_uit );
947 vlc_mutex_unlock( &p_uit->p_u->lock );
952 update_iterator_GetData( p_uit );
953 vlc_mutex_unlock( &p_uit->p_u->lock );
954 return UPDATE_SUCCESS|UPDATE_RELEASE|UPDATE_FILE;
959 * Finds the next mirror in the update tree
961 * \param update iterator
962 * \return UPDATE_FAIL if we can't find the next mirror, UPDATE_SUCCESS|UPDATE_MIRROR otherwise
964 unsigned int update_iterator_NextMirror( update_iterator_t *p_uit )
966 if( !p_uit ) return UPDATE_FAIL;
967 vlc_mutex_lock( &p_uit->p_u->lock );
969 if( p_uit->i_m >= p_uit->p_u->i_mirrors ) p_uit->i_m = -1;
970 update_iterator_GetData( p_uit );
971 vlc_mutex_unlock( &p_uit->p_u->lock );
972 return p_uit->i_m == -1 ? UPDATE_FAIL : UPDATE_SUCCESS|UPDATE_MIRROR;
976 * Finds the previous mirror in the update tree
978 * \param update iterator
979 * \return UPDATE_FAIL if we can't find a previous mirror, UPDATE_SUCCESS|UPDATE_MIRROR otherwise
981 unsigned int update_iterator_PrevMirror( update_iterator_t *p_uit )
983 if( !p_uit ) return UPDATE_FAIL;
984 vlc_mutex_lock( &p_uit->p_u->lock );
986 update_iterator_GetData( p_uit );
987 vlc_mutex_unlock( &p_uit->p_u->lock );
988 return p_uit->i_m == -1 ? UPDATE_FAIL : UPDATE_SUCCESS|UPDATE_MIRROR;
992 * Change the update iterator's position in the file and mirrors tree
993 * If position is negative, don't change it
995 * \param i_m position in mirrors list
996 * \param i_r position in releases list
997 * \param i_f position in release's files list
998 * \return UPDATE_FAIL when changing position fails or position wasn't changed, a combination of UPDATE_MIRROR, UPDATE_RELEASE and UPDATE_FILE otherwise
1000 unsigned int update_iterator_ChooseMirrorAndFile( update_iterator_t *p_uit,
1001 int i_m, int i_r, int i_f )
1003 unsigned int i_val = 0;
1005 if( !p_uit ) return 0;
1006 vlc_mutex_lock( &p_uit->p_u->lock );
1010 if( i_m < p_uit->p_u->i_mirrors )
1012 if( i_m != p_uit->i_m )
1013 i_val |= UPDATE_MIRROR;
1021 if( i_r < p_uit->p_u->i_releases )
1023 if( i_r != p_uit->i_r )
1024 i_val |= UPDATE_FILE;
1032 if( i_r >= 0 && i_r < p_uit->p_u->i_releases
1033 && i_f < p_uit->p_u->p_releases[p_uit->i_r].i_files )
1035 if( i_f != p_uit->i_f )
1036 i_val |= UPDATE_FILE;
1042 update_iterator_GetData( p_uit );
1043 vlc_mutex_unlock( &p_uit->p_u->lock );
1045 if( ( i_m < 0 || p_uit->i_m >= 0 )
1046 && ( i_r < 0 || p_uit->i_r >= 0 )
1047 && ( i_f < 0 || p_uit->i_f >= 0 ) )
1049 /* Everything worked */
1050 return UPDATE_SUCCESS|i_val;
1054 /* Something failed */
1060 * Fills the iterator data (file, release and mirror structs)
1061 * The update struct should be locked before calling this function.
1063 * \param p_uit update iterator
1066 void update_iterator_GetData( update_iterator_t *p_uit )
1068 struct update_release_t *p_r = NULL;
1069 struct update_file_t *p_f = NULL;
1070 struct update_mirror_t *p_m = NULL;
1072 update_iterator_ClearData( p_uit );
1074 if( p_uit->i_m >= 0 )
1076 p_m = p_uit->p_u->p_mirrors + p_uit->i_m;
1077 p_uit->mirror.psz_name = STRDUP( p_m->psz_name );
1078 p_uit->mirror.psz_location = STRDUP( p_m->psz_location );
1079 p_uit->mirror.psz_type = STRDUP( p_m->psz_type );
1082 if( p_uit->i_r >= 0 )
1084 p_r = p_uit->p_u->p_releases + p_uit->i_r;
1085 asprintf( &p_uit->release.psz_version, "%s.%s.%s-%s",
1090 p_uit->release.psz_svn_revision = STRDUP( p_r->psz_svn_revision );
1091 p_uit->release.i_type = p_r->i_type;
1092 p_uit->release.i_status = p_r->i_status;
1093 if( p_uit->i_f >= 0 )
1095 p_f = p_r->p_files + p_uit->i_f;
1096 p_uit->file.i_type = p_f->i_type;
1097 p_uit->file.psz_md5 = STRDUP( p_f->psz_md5 );
1098 p_uit->file.l_size = p_f->l_size;
1099 p_uit->file.psz_description = STRDUP( p_f->psz_description);
1100 if( p_f->psz_url[0] == '/' )
1104 asprintf( &p_uit->file.psz_url, "%s%s",
1105 p_m->psz_base_url, p_f->psz_url );
1110 p_uit->file.psz_url = STRDUP( p_f->psz_url );
1117 * Clears the iterator data (file, release and mirror structs)
1119 * \param p_uit update iterator
1122 void update_iterator_ClearData( update_iterator_t *p_uit )
1124 p_uit->file.i_type = UPDATE_FILE_TYPE_NONE;
1125 FREENULL( p_uit->file.psz_md5 );
1126 p_uit->file.l_size = 0;
1127 FREENULL( p_uit->file.psz_description );
1128 FREENULL( p_uit->file.psz_url );
1129 FREENULL( p_uit->release.psz_version );
1130 FREENULL( p_uit->release.psz_svn_revision );
1131 p_uit->release.i_type = UPDATE_RELEASE_TYPE_UNSTABLE;
1132 p_uit->release.i_status = UPDATE_RELEASE_STATUS_NONE;
1133 FREENULL( p_uit->mirror.psz_name );
1134 FREENULL( p_uit->mirror.psz_location );
1135 FREENULL( p_uit->mirror.psz_type );
1139 * Perform an action on the update iterator
1140 * Only the first matching action is performed.
1142 * \param p_uit update iterator
1143 * \param i_action update action bitmask. can be a combination of UPDATE_NEXT, UPDATE_PREV, UPDATE_MIRROR, UPDATE_RELEASE, UPDATE_FILE, UPDATE_RESET
1144 * \return UPDATE_FAIL if action fails, UPDATE_SUCCESS|(combination of UPDATE_MIRROR, UPDATE_RELEASE and UPDATE_FILE if these changed) otherwise
1146 unsigned int update_iterator_Action( update_iterator_t *p_uit, int i_action )
1148 if( i_action & UPDATE_RESET )
1150 return update_iterator_Reset( p_uit );
1153 if( i_action & UPDATE_MIRROR )
1155 if( i_action & UPDATE_PREV )
1157 return update_iterator_PrevMirror( p_uit );
1161 return update_iterator_NextMirror( p_uit );
1164 /*else if( i_action & UPDATE_RELEASE )
1166 if( i_action & UPDATE_PREV )
1168 return update_iterator_PrevRelease( p_uit );
1172 return update_iterator_NextRelease( p_uit );
1175 else if( i_action & UPDATE_FILE )
1177 if( i_action & UPDATE_PREV )
1179 return update_iterator_PrevFile( p_uit );
1183 return update_iterator_NextFile( p_uit );
1188 return UPDATE_SUCCESS;
1193 * Object to launch download thread in a different object
1197 char *psz_dest; //< Download destination
1198 char *psz_src; //< Download source
1199 char *psz_status; //< Download status displayed in progress dialog
1200 } download_thread_t;
1202 void update_download_for_real( download_thread_t *p_this );
1205 * Download the file selected by the update iterator. This function will
1206 * launch the download in a new thread (downloads can be long)
1208 * \param p_uit update iterator
1209 * \param psz_dest destination file path
1212 void update_download( update_iterator_t *p_uit, char *psz_dest )
1214 download_thread_t *p_dt =
1215 vlc_object_create( p_uit->p_u->p_libvlc, sizeof( download_thread_t ) );
1217 p_dt->psz_dest = strdup( psz_dest );
1218 p_dt->psz_src = strdup( p_uit->file.psz_url );
1219 asprintf( &p_dt->psz_status, "%s - %s (%s)\nSource: %s\nDestination: %s",
1220 p_uit->file.psz_description, p_uit->release.psz_version,
1221 p_uit->release.psz_svn_revision, p_uit->file.psz_url,
1224 vlc_thread_create( p_dt, "download thread", update_download_for_real,
1225 VLC_THREAD_PRIORITY_LOW, VLC_FALSE );
1229 * Convert a long int size in bytes to a string
1231 * \param l_size the size in bytes
1232 * \return the size as a string
1234 char *size_str( long int l_size )
1238 asprintf( &psz_tmp, "%.1f GB", (float)l_size/(1<<30) );
1240 asprintf( &psz_tmp, "%.1f MB", (float)l_size/(1<<20) );
1241 else if( l_size >> 10 )
1242 asprintf( &psz_tmp, "%.1f kB", (float)l_size/(1<<10) );
1244 asprintf( &psz_tmp, "%ld B", l_size );
1249 * The true download function.
1251 * \param p_this the download_thread_t object
1254 void update_download_for_real( download_thread_t *p_this )
1256 char *psz_dest = p_this->psz_dest;
1257 char *psz_src = p_this->psz_src;
1259 libvlc_int_t *p_libvlc = p_this->p_libvlc;
1261 FILE *p_file = NULL;
1267 long int l_size, l_done = 0;
1269 vlc_thread_ready( p_this );
1271 asprintf( &psz_status, "%s\nDownloading... 0.0/? %.1f%% done",
1272 p_this->psz_status, 0.0 );
1273 i_progress = intf_UserProgress( p_libvlc, "Downloading...",
1274 psz_status, 0.0, 0 );
1276 p_stream = stream_UrlNew( p_libvlc, psz_src );
1279 msg_Err( p_libvlc, "Failed to open %s for reading", psz_src );
1280 intf_UserFatal( p_libvlc, VLC_TRUE, "Error while Downloading...",
1281 "VLC failed to open %s for reading.", psz_src );
1282 intf_UserHide( p_libvlc, i_progress );
1287 p_file = utf8_fopen( psz_dest, "w" );
1290 msg_Err( p_libvlc, "Failed to open %s for writing", psz_dest );
1291 intf_UserFatal( p_libvlc, VLC_TRUE, "Error while Downloading...",
1292 "VLC failed to open %s for writing.", psz_dest );
1293 intf_UserHide( p_libvlc, i_progress );
1298 char *psz_s1; char *psz_s2;
1300 l_size = stream_Size(p_stream);
1301 p_buffer = (void *)malloc( 1<<10 );
1303 while( ( l_read = stream_Read( p_stream, p_buffer, 1<<10 ) ) )
1307 fwrite( p_buffer, l_read, 1, p_file );
1311 f_progress = 100.0*(float)l_done/(float)l_size;
1312 psz_s1 = size_str( l_done );
1313 psz_s2 = size_str( l_size );
1314 asprintf( &psz_status, "%s\nDownloading... %s/%s (%.1f%%) done",
1315 p_this->psz_status, psz_s1, psz_s2, f_progress );
1316 free( psz_s1 ); free( psz_s2 );
1318 intf_ProgressUpdate( p_libvlc, i_progress,
1319 psz_status, f_progress, 0 );
1324 stream_Delete( p_stream );
1327 psz_s2 = size_str( l_size );
1328 asprintf( &psz_status, "%s\nDone %s (100.00%%)",
1329 p_this->psz_status, psz_s2 );
1331 intf_ProgressUpdate( p_libvlc, i_progress, psz_status, 100.0, 0 );
1336 free( p_this->psz_dest );
1337 free( p_this->psz_src );
1338 free( p_this->psz_status );
1341 CloseHandle( p_this->thread_id );
1344 vlc_object_destroy( p_this );