Commit 09b9702d authored by Rémi Duraffort's avatar Rémi Duraffort

Modify the update system : I will add more functionnality but this is the beginning

parent 1f94c930
...@@ -36,45 +36,11 @@ ...@@ -36,45 +36,11 @@
* @{ * @{
*/ */
#define UPDATE_FILE_TYPE_ALL (~0) enum
#define UPDATE_FILE_TYPE_NONE 0
#define UPDATE_FILE_TYPE_UNDEF 1
#define UPDATE_FILE_TYPE_INFO 2
#define UPDATE_FILE_TYPE_SOURCE 4
#define UPDATE_FILE_TYPE_BINARY 8
#define UPDATE_FILE_TYPE_PLUGIN 16
#define UPDATE_RELEASE_STATUS_ALL (~0)
#define UPDATE_RELEASE_STATUS_NONE 0
#define UPDATE_RELEASE_STATUS_OLDER 1
#define UPDATE_RELEASE_STATUS_EQUAL 2
#define UPDATE_RELEASE_STATUS_NEWER 4
#define UPDATE_RELEASE_TYPE_STABLE 1
#define UPDATE_RELEASE_TYPE_TESTING 2
#define UPDATE_RELEASE_TYPE_UNSTABLE 4
#define UPDATE_FAIL 0
#define UPDATE_SUCCESS 1
#define UPDATE_NEXT 0
#define UPDATE_PREV 2
#define UPDATE_MIRROR 4
#define UPDATE_RELEASE 8
#define UPDATE_FILE 16
#define UPDATE_RESET 32
/**
* Describes an update file
*/
struct update_file_t
{ {
int i_type; ///< File type UpdateReleaseStatusOlder,
char* psz_md5; ///< MD5 hash UpdateReleaseStatusEqual,
long int l_size; ///< File size in bytes UpdateReleaseStatusNewer
char* psz_url; ///< Relative (to a mirror) or absolute url
char* psz_description; ///< Plain text description
}; };
/** /**
...@@ -82,32 +48,13 @@ struct update_file_t ...@@ -82,32 +48,13 @@ struct update_file_t
*/ */
struct update_release_t struct update_release_t
{ {
char* psz_major; ///< Version major string int i_major; ///< Version major
char* psz_minor; ///< Version minor string int i_minor; ///< Version minor
char* psz_revision; ///< Version revision string int i_revision; ///< Version revision
char* psz_extra; ///< Version extra string char* psz_svnrev; ///< SVN revision
char* psz_extra; ///< Version extra
char* psz_svn_revision; ///< SVN revision char* psz_url; ///< Download URL
char* psz_desc; ///< Release description
int i_type; ///< Release type
int i_status; ///< Release status compared to current VLC version
struct update_file_t* p_files; ///< Files list
int i_files; ///< Number of files in the files list
};
/**
* Describes a mirror
*/
struct update_mirror_t
{
char *psz_name; ///< Mirror name
char *psz_location; ///< Mirror geographical location
char *psz_type; ///< Mirror type (FTP, HTTP, ...)
char *psz_base_url; ///< Mirror base url
}; };
/** /**
...@@ -116,60 +63,17 @@ struct update_mirror_t ...@@ -116,60 +63,17 @@ struct update_mirror_t
struct update_t struct update_t
{ {
libvlc_int_t *p_libvlc; libvlc_int_t *p_libvlc;
vlc_mutex_t lock; vlc_mutex_t lock;
struct update_release_t release; ///< Release (version)
struct update_release_t *p_releases; ///< Releases (version) list
int i_releases; ///< Number of releases
vlc_bool_t b_releases; ///< True if we have a releases list
struct update_mirror_t *p_mirrors; ///< Mirrors list
int i_mirrors; ///< Number of mirrors
vlc_bool_t b_mirrors; ///< True if we have a mirrors list
}; };
/**
* The update iterator structure. Usefull to browse the update object seamlessly
*/
struct update_iterator_t
{
update_t *p_u; ///< Pointer to VLC update object
int i_r; ///< Position in the releases list
int i_f; ///< Position in the release's files list
int i_m; ///< Position in the mirrors list
int i_t; ///< File type bitmask
int i_rs; ///< Release status bitmask
int i_rt; ///< Release type bitmask
struct update_file_t file; ///< Local copy of the current file's information
struct
{
char *psz_version; ///< Version string
char *psz_svn_revision; ///< SVN revision
int i_status; ///< Status
int i_type; ///< Type
} release; ///< Local 'copy' of the current release's information
struct
{
char *psz_name; ///< Name
char *psz_location; ///< Geographical location
char *psz_type; ///< Type (HTTP, FTP, ...)
} mirror; ///< Local 'copy' of the current mirror's information
};
#define update_New( a ) __update_New( VLC_OBJECT( a ) ) #define update_New( a ) __update_New( VLC_OBJECT( a ) )
VLC_EXPORT( update_t *, __update_New, ( vlc_object_t * ) ); VLC_EXPORT( update_t *, __update_New, ( vlc_object_t * ) );
VLC_EXPORT( void, update_Delete, (update_t * ) ); VLC_EXPORT( void, update_Delete, ( update_t * ) );
VLC_EXPORT( void, update_Check, ( update_t *, vlc_bool_t ) ); VLC_EXPORT( void, update_Check, ( update_t * ) );
VLC_EXPORT( int, update_CompareReleaseToCurrent, ( update_t * ) );
VLC_EXPORT( update_iterator_t *, update_iterator_New, ( update_t * ) );
VLC_EXPORT( void, update_iterator_Delete, ( update_iterator_t * ) );
VLC_EXPORT( unsigned int, update_iterator_Action, ( update_iterator_t *, int ) );
VLC_EXPORT( unsigned int, update_iterator_ChooseMirrorAndFile, ( update_iterator_t *, int, int, int ) );
VLC_EXPORT( void, update_download, ( update_iterator_t *, const char * ) );
/** /**
* @} * @}
......
...@@ -96,7 +96,7 @@ static int AudioConfig ( vlc_object_t *, char const *, ...@@ -96,7 +96,7 @@ static int AudioConfig ( vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void * ); vlc_value_t, vlc_value_t, void * );
static int Menu ( vlc_object_t *, char const *, static int Menu ( vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void * ); vlc_value_t, vlc_value_t, void * );
static void checkUpdates( intf_thread_t *p_intf, char *psz_arg ); static void checkUpdates( intf_thread_t *p_intf );
/* Status Callbacks */ /* Status Callbacks */
static int TimeOffsetChanged( vlc_object_t *, char const *, static int TimeOffsetChanged( vlc_object_t *, char const *,
...@@ -752,7 +752,7 @@ static void Run( intf_thread_t *p_intf ) ...@@ -752,7 +752,7 @@ static void Run( intf_thread_t *p_intf )
} }
else if( !strcmp( psz_cmd, "check-updates" ) ) else if( !strcmp( psz_cmd, "check-updates" ) )
{ {
checkUpdates( p_intf, psz_arg ); checkUpdates( p_intf );
} }
else if( !strcmp( psz_cmd, "key" ) || !strcmp( psz_cmd, "hotkey" ) ) else if( !strcmp( psz_cmd, "key" ) || !strcmp( psz_cmd, "hotkey" ) )
{ {
...@@ -2105,116 +2105,20 @@ static input_item_t *parse_MRL( intf_thread_t *p_intf, char *psz_mrl ) ...@@ -2105,116 +2105,20 @@ static input_item_t *parse_MRL( intf_thread_t *p_intf, char *psz_mrl )
/***************************************************************************** /*****************************************************************************
* checkUpdates : check for updates * checkUpdates : check for updates
****************************************************************************/ ****************************************************************************/
static void checkUpdates( intf_thread_t *p_intf, char *psz_arg ) static void checkUpdates( intf_thread_t *p_intf )
{ {
update_iterator_t *p_uit;
update_t *p_u = update_New( p_intf ); update_t *p_u = update_New( p_intf );
if( p_u == NULL ) return; if( p_u == NULL ) return;
p_uit = update_iterator_New( p_u );
if( p_uit ) update_Check( p_u );
{ msg_rc( "\nChecking for updates" );
int s = 0, t = 0;
if( update_CompareReleaseToCurrent( p_u ) == UpdateReleaseStatusNewer )
if( strstr( psz_arg, "newer" ) ) msg_rc( "\n+----[ VLC %i.%i.%i%s ] ", p_u->release.i_major,
s |= UPDATE_RELEASE_STATUS_NEWER; p_u->release.i_minor,
if( strstr( psz_arg, "equal" ) ) p_u->release.i_revision,
s |= UPDATE_RELEASE_STATUS_EQUAL; p_u->release.psz_extra );
if( strstr( psz_arg, "older" ) )
s |= UPDATE_RELEASE_STATUS_OLDER;
if( s ) p_uit->i_rs = s;
else p_uit->i_rs = UPDATE_RELEASE_STATUS_NEWER;
if( strstr( psz_arg, "undef" ) )
t |= UPDATE_FILE_TYPE_UNDEF;
if( strstr( psz_arg, "info" ) )
t |= UPDATE_FILE_TYPE_INFO;
if( strstr( psz_arg, "source" ) )
t |= UPDATE_FILE_TYPE_SOURCE;
if( strstr( psz_arg, "binary" ) )
t |= UPDATE_FILE_TYPE_BINARY;
if( strstr( psz_arg, "plugin" ) )
t |= UPDATE_FILE_TYPE_PLUGIN;
if( t ) p_uit->i_t = t;
update_Check( p_u, VLC_FALSE );
update_iterator_Action( p_uit, UPDATE_MIRROR );
msg_rc( "\nUsing mirror: %s (%s) [%s]",
p_uit->mirror.psz_name,
p_uit->mirror.psz_location,
p_uit->mirror.psz_type );
while( (s = update_iterator_Action( p_uit, UPDATE_FILE )) != UPDATE_FAIL )
{
char *psz_tmp;
if( s & UPDATE_RELEASE )
{
switch( p_uit->release.i_status )
{
case UPDATE_RELEASE_STATUS_OLDER:
psz_tmp = strdup( "older" );
break;
case UPDATE_RELEASE_STATUS_EQUAL:
psz_tmp = strdup( "equal" );
break;
case UPDATE_RELEASE_STATUS_NEWER:
psz_tmp = strdup( "newer" );
break;
default:
psz_tmp = strdup( "?!?" );
break;
}
msg_rc( "\n+----[ VLC %s %s (%s) ] ",
p_uit->release.psz_version,
p_uit->release.psz_svn_revision,
psz_tmp );
free( psz_tmp );
}
switch( p_uit->file.i_type )
{
case UPDATE_FILE_TYPE_UNDEF:
psz_tmp = strdup( "undef" );
break;
case UPDATE_FILE_TYPE_INFO:
psz_tmp = strdup( "info" );
break;
case UPDATE_FILE_TYPE_SOURCE:
psz_tmp = strdup( "source" );
break;
case UPDATE_FILE_TYPE_BINARY:
psz_tmp = strdup( "binary" );
break;
case UPDATE_FILE_TYPE_PLUGIN:
psz_tmp = strdup( "plugin" );
break;
default:
psz_tmp = strdup( "?!?" );
break;
}
msg_rc( "| %s (%s)", p_uit->file.psz_description, psz_tmp );
free( psz_tmp );
if( p_uit->file.l_size )
{
if( p_uit->file.l_size > 1024 * 1024 * 1024 )
asprintf( &psz_tmp, "(%ld GB)",
p_uit->file.l_size / (1024*1024*1024) );
if( p_uit->file.l_size > 1024 * 1024 )
asprintf( &psz_tmp, "(%ld MB)",
p_uit->file.l_size / (1024*1024) );
else if( p_uit->file.l_size > 1024 )
asprintf( &psz_tmp, "(%ld kB)",
p_uit->file.l_size / 1024 );
else
asprintf( &psz_tmp, "(%ld B)", p_uit->file.l_size );
}
else else
{ msg_rc( "\n+----Last version" );
psz_tmp = strdup( "" );
}
msg_rc( "| %s %s", p_uit->file.psz_url, psz_tmp );
msg_rc( "+----" );
free( psz_tmp );
}
msg_rc( "" );
update_iterator_Delete( p_uit );
}
update_Delete( p_u ); update_Delete( p_u );
} }
...@@ -35,15 +35,12 @@ ...@@ -35,15 +35,12 @@
#include <QFile> #include <QFile>
#include <QLabel> #include <QLabel>
#include <QString> #include <QString>
#include <QCheckBox>
#include <QGroupBox>
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QFileDialog>
HelpDialog *HelpDialog::instance = NULL; HelpDialog *HelpDialog::instance = NULL;
HelpDialog::HelpDialog( intf_thread_t *_p_intf) : QVLCFrame( _p_intf ) HelpDialog::HelpDialog( intf_thread_t *_p_intf ) : QVLCFrame( _p_intf )
{ {
setWindowTitle( qtr( "Help" ) ); setWindowTitle( qtr( "Help" ) );
resize( 600, 560 ); resize( 600, 560 );
...@@ -105,13 +102,13 @@ AboutDialog::AboutDialog( intf_thread_t *_p_intf) : QVLCFrame( _p_intf ) ...@@ -105,13 +102,13 @@ AboutDialog::AboutDialog( intf_thread_t *_p_intf) : QVLCFrame( _p_intf )
+ qtr( "You are using the new Qt4 Interface.\n" ) + qtr( "You are using the new Qt4 Interface.\n" )
+ qtr( "Compiled by " ) + qfu( VLC_CompileBy() )+ "@" + qtr( "Compiled by " ) + qfu( VLC_CompileBy() )+ "@"
+ qfu( VLC_CompileDomain() ) + ".\n" + qfu( VLC_CompileDomain() ) + ".\n"
+ "Compiler: " + qfu( VLC_Compiler() ) +".\n" + "Compiler: " + qfu( VLC_Compiler() ) + ".\n"
+ qtr( "Based on SVN revision: " ) + qfu( VLC_Changeset() ) + qtr( "Based on SVN revision: " ) + qfu( VLC_Changeset() )
+ ".\n\n" + ".\n\n"
+ qtr( "This program comes with NO WARRANTY, to the extent " + qtr( "This program comes with NO WARRANTY, to the extent "
"permitted by the law; read the distribution tab.\n\n" ) "permitted by the law; read the distribution tab.\n\n" )
+ "The VideoLAN team <videolan@videolan.org> \n" + "The VideoLAN team <videolan@videolan.org> \n"
"http://www.videolan.org/\n") ; "http://www.videolan.org/\n" );
infoLabel->setWordWrap( infoLabel ); infoLabel->setWordWrap( infoLabel );
QLabel *iconVLC2 = new QLabel; QLabel *iconVLC2 = new QLabel;
...@@ -129,7 +126,7 @@ AboutDialog::AboutDialog( intf_thread_t *_p_intf) : QVLCFrame( _p_intf ) ...@@ -129,7 +126,7 @@ AboutDialog::AboutDialog( intf_thread_t *_p_intf) : QVLCFrame( _p_intf )
QWidget *thanksWidget = new QWidget( this ); QWidget *thanksWidget = new QWidget( this );
QVBoxLayout *thanksLayout = new QVBoxLayout( thanksWidget ); QVBoxLayout *thanksLayout = new QVBoxLayout( thanksWidget );
QLabel *thanksLabel = new QLabel( qtr("We would like to thank the whole " QLabel *thanksLabel = new QLabel( qtr( "We would like to thank the whole "
"community, the testers, our users and the following people " "community, the testers, our users and the following people "
"(and the missing ones...) for their collaboration to " "(and the missing ones...) for their collaboration to "
"provide the best software." ) ); "provide the best software." ) );
...@@ -165,45 +162,32 @@ void AboutDialog::close() ...@@ -165,45 +162,32 @@ void AboutDialog::close()
UpdateDialog *UpdateDialog::instance = NULL; UpdateDialog *UpdateDialog::instance = NULL;
UpdateDialog::UpdateDialog( intf_thread_t *_p_intf) : QVLCFrame( _p_intf ) UpdateDialog::UpdateDialog( intf_thread_t *_p_intf ) : QVLCFrame( _p_intf )
{ {
setWindowTitle( qtr( "Update" ) ); setWindowTitle( qtr( "Update" ) );
resize( 230, 180 ); resize( 320, 120 );
QGridLayout *layout = new QGridLayout( this ); QGridLayout *layout = new QGridLayout( this );
updateBrowser = new QTextBrowser( this );
updateBrowser->setOpenExternalLinks( true );
updateBrowser->setHtml( qtr( "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=\"utf-8\" /></head> \
<body><center>Push the update button to get the updates</center></body></html>" ) );
QPushButton *closeButton = new QPushButton( qtr( "&Close" ) ); QPushButton *closeButton = new QPushButton( qtr( "&Close" ) );
updateButton = new QPushButton( qtr( "&Update List" ) ); QPushButton *updateButton = new QPushButton( qtr( "&Update List" ) );
updateButton->setDefault( true ); updateButton->setDefault( true );
QDialogButtonBox *buttonBox = new QDialogButtonBox(Qt::Horizontal); QDialogButtonBox *buttonBox = new QDialogButtonBox( Qt::Horizontal );
buttonBox->addButton( updateButton, QDialogButtonBox::ActionRole ); buttonBox->addButton( updateButton, QDialogButtonBox::ActionRole );
buttonBox->addButton( closeButton, QDialogButtonBox::AcceptRole ); buttonBox->addButton( closeButton, QDialogButtonBox::AcceptRole );
QGroupBox *checkGroup = new QGroupBox( qtr( "Select Package" ) ); layout->addWidget( updateBrowser, 0, 0 );
QGridLayout *checkLayout = new QGridLayout( checkGroup );
checkInfo = new QCheckBox( qtr( "Information" ) );
checkSource = new QCheckBox( qtr( "Sources" ) );
checkBinary = new QCheckBox( qtr( "Binary" ) );
checkPlugin = new QCheckBox( qtr( "Plugin" ) );
checkInfo->setDisabled( true );
checkSource->setDisabled( true );
checkBinary->setDisabled( true );
checkPlugin->setDisabled( true );
checkLayout->addWidget( checkInfo, 0, 0 );
checkLayout->addWidget( checkSource, 1, 0 );
checkLayout->addWidget( checkBinary, 2, 0 );
checkLayout->addWidget( checkPlugin, 3, 0 );
layout->addWidget( checkGroup, 0, 0 );
layout->addWidget( buttonBox, 1, 0 ); layout->addWidget( buttonBox, 1, 0 );
BUTTONACT( updateButton, updateOrUpload() ); BUTTONACT( updateButton, updateOrUpload() );
BUTTONACT( closeButton, close() ); BUTTONACT( closeButton, close() );
p_update = update_New( _p_intf ); p_update = update_New( _p_intf );
b_updated = false;
} }
UpdateDialog::~UpdateDialog() UpdateDialog::~UpdateDialog()
...@@ -218,101 +202,18 @@ void UpdateDialog::close() ...@@ -218,101 +202,18 @@ void UpdateDialog::close()
void UpdateDialog::updateOrUpload() void UpdateDialog::updateOrUpload()
{ {
if( !p_update ) return; update_Check( p_update );
if( !b_updated )
{
update_Check( p_update, VLC_FALSE );
update_iterator_t *p_updateit = update_iterator_New( p_update );
bool b_download = false;
if( p_updateit )
{
p_updateit->i_rs = UPDATE_RELEASE_STATUS_NEWER;
p_updateit->i_t = UPDATE_FILE_TYPE_ALL;
update_iterator_Action( p_updateit, UPDATE_MIRROR );
while( update_iterator_Action( p_updateit, UPDATE_FILE ) != UPDATE_FAIL )
{
switch( p_updateit->file.i_type )
{
case UPDATE_FILE_TYPE_INFO:
checkInfo->setText( qtr( "Information" ) + " (" + qfu( p_updateit->release.psz_version ) + ")" );
checkInfo->setDisabled( false );
checkInfo->setCheckState( Qt::Checked );
b_download = true;
break;
case UPDATE_FILE_TYPE_SOURCE:
checkSource->setText( qtr( "Source" ) + " (" + qfu( p_updateit->release.psz_version ) + ")" );
checkSource->setDisabled( false );
checkSource->setCheckState( Qt::Checked );
b_download = true;
break;
case UPDATE_FILE_TYPE_BINARY:
checkBinary->setText( qtr( "Binary" ) + " (" + qfu( p_updateit->release.psz_version ) + ")" );
checkBinary->setDisabled( false );
checkBinary->setCheckState( Qt::Checked );
b_download = true;
break;
case UPDATE_FILE_TYPE_PLUGIN:
checkPlugin->setText( qtr( "Plugin" ) + " (" + qfu( p_updateit->release.psz_version ) + ")");
checkPlugin->setDisabled( false );
checkPlugin->setCheckState( Qt::Checked );
b_download = true;
break;
default:
break;
}
}
}
if( b_download )
{
updateButton->setText(qtr( "Download" ) );
b_updated = true;
}
update_iterator_Delete( p_updateit );
}
else
{
update_iterator_t *p_updateit = update_iterator_New( p_update );
bool b_download = false;
if( p_updateit )
{
QString saveDir = QFileDialog::getExistingDirectory( this, qtr( "Choose a directory..." ),
qfu( p_intf->p_libvlc->psz_homedir ) );
p_updateit->i_rs = UPDATE_RELEASE_STATUS_NEWER;
p_updateit->i_t = UPDATE_FILE_TYPE_ALL;
update_iterator_Action( p_updateit, UPDATE_MIRROR );
while( update_iterator_Action( p_updateit, UPDATE_FILE ) != UPDATE_FAIL ) if( update_CompareReleaseToCurrent( p_update ) == UpdateReleaseStatusNewer )
{ {
b_download = false; updateBrowser->setHtml( qtr( "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=\"utf-8\" /></head> \
switch( p_updateit->file.i_type ) <body><center><p>" ) + qtu( (QString)p_update->release.psz_desc ) +
{ qtr( "</p>You can download the latest version of VLC <a href=\"" ) +
case UPDATE_FILE_TYPE_INFO: qtu( (QString)p_update->release.psz_url ) + qtr( "\">here</a></center></body></html>" ) );
if( checkInfo->isChecked() )
b_download = true;
break;
case UPDATE_FILE_TYPE_SOURCE:
if( checkSource->isChecked() )
b_download = true;
break;
case UPDATE_FILE_TYPE_BINARY:
if( checkBinary->isChecked() )
b_download = true;
break;
case UPDATE_FILE_TYPE_PLUGIN:
if( checkPlugin->isChecked() )
b_download = true;
break;
default:
break;
} }
if( b_download ) else
{ {
QString strFileName = p_updateit->file.psz_url; updateBrowser->setHtml( "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=\"utf-8\" /></head> \
strFileName.remove( 0, strFileName.lastIndexOf( "/" ) + 1 ); <body><center>You have the latest version of VLC.</center></body></html>" );
update_download( p_updateit, qtu( ( saveDir + strFileName ) ) );
}
}
}
} }
} }
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
#include "util/qvlcframe.hpp" #include "util/qvlcframe.hpp"
class QPushButton; class QPushButton;
class QCheckBox; class QTextBrowser;
class HelpDialog : public QVLCFrame class HelpDialog : public QVLCFrame
{ {
...@@ -44,7 +44,7 @@ public: ...@@ -44,7 +44,7 @@ public:
virtual ~HelpDialog(); virtual ~HelpDialog();
private: private:
HelpDialog( intf_thread_t *); HelpDialog( intf_thread_t * );
static HelpDialog *instance; static HelpDialog *instance;
public slots: public slots:
void close(); void close();
...@@ -58,13 +58,13 @@ public: ...@@ -58,13 +58,13 @@ public:
static AboutDialog * getInstance( intf_thread_t *p_intf ) static AboutDialog * getInstance( intf_thread_t *p_intf )
{ {
if( !instance) if( !instance)
instance = new AboutDialog( p_intf); instance = new AboutDialog( p_intf );
return instance; return instance;
} }
virtual ~AboutDialog(); virtual ~AboutDialog();
private: private:
AboutDialog( intf_thread_t *); AboutDialog( intf_thread_t * );
static AboutDialog *instance; static AboutDialog *instance;
public slots: public slots:
void close(); void close();
...@@ -77,22 +77,17 @@ class UpdateDialog : public QVLCFrame ...@@ -77,22 +77,17 @@ class UpdateDialog : public QVLCFrame
public: public:
static UpdateDialog * getInstance( intf_thread_t *p_intf ) static UpdateDialog * getInstance( intf_thread_t *p_intf )
{ {
if( !instance) if( !instance )
instance = new UpdateDialog( p_intf); instance = new UpdateDialog( p_intf );
return instance; return instance;
} }
virtual ~UpdateDialog(); virtual ~UpdateDialog();
private: private:
UpdateDialog( intf_thread_t *); UpdateDialog( intf_thread_t * );
static UpdateDialog *instance; static UpdateDialog *instance;
QPushButton *updateButton;
QCheckBox *checkInfo;
QCheckBox *checkSource;
QCheckBox *checkBinary;
QCheckBox *checkPlugin;
update_t *p_update; update_t *p_update;
bool b_updated; QTextBrowser *updateBrowser;
private slots: private slots:
void close(); void close();
void updateOrUpload(); void updateOrUpload();
......
...@@ -21,11 +21,6 @@ ...@@ -21,11 +21,6 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/ *****************************************************************************/
/* TODO
* --> check release types.
* --> make sure that the version comparision method is ok.
*/
/** /**
* \file * \file
* This file contains functions related to VLC and plugins update management * This file contains functions related to VLC and plugins update management
...@@ -45,65 +40,44 @@ ...@@ -45,65 +40,44 @@
#include <vlc_block.h> #include <vlc_block.h>
#include <vlc_stream.h> #include <vlc_stream.h>
#include <vlc_xml.h>
#include <vlc_interface.h> #include <vlc_interface.h>
#include <vlc_charset.h> #include <vlc_charset.h>
#include <vlc_md5.h>
/***************************************************************************** /*****************************************************************************
* Misc defines * Misc defines
*****************************************************************************/ *****************************************************************************/
/* All release notes and source packages should match on "*" //#define UPDATE_VLC_STATUS_URL "http://zen.via.ecp.fr/~ivoire/videolan/update"
* Only binary installers are OS specific ( we only provide these
* for Win32, Mac OS X, WincCE, beos(?) ) */
#if defined( UNDER_CE ) #if defined( UNDER_CE )
# define UPDATE_VLC_OS "*" # define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-ce"
# define UPDATE_VLC_ARCH "*"
#elif defined( WIN32 ) #elif defined( WIN32 )
# define UPDATE_VLC_OS "windows" # define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-win-x86"
# define UPDATE_VLC_ARCH "i386"
#elif defined( __APPLE__ ) #elif defined( __APPLE__ )
# define UPDATE_VLC_OS "macosx" # define UPDATE_VLC_OS "macosx"
# if defined( __powerpc__ ) || defined( __ppc__ ) || defined( __ppc64__ ) # if defined( __powerpc__ ) || defined( __ppc__ ) || defined( __ppc64__ )
# define UPDATE_VLC_ARCH "ppc" # define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-mac-ppc"
# else # else
# define UPDATE_VLC_ARCH "x86" # define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-mac-x86"
# endif # endif
#elif defined( SYS_BEOS ) #elif defined( SYS_BEOS )
# define UPDATE_VLC_OS "beos" # define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-beos-x86"
# define UPDATE_VLC_ARCH "i386"
#else #else
# define UPDATE_VLC_OS "*" # define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status"
# define UPDATE_VLC_ARCH "*"
#endif #endif
#define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status.xml"
#define UPDATE_VLC_MIRRORS_URL "http://update.videolan.org/mirrors.xml"
#define STRDUP( a ) ( a ? strdup( a ) : NULL ) #define STRDUP( a ) ( a ? strdup( a ) : NULL )
/***************************************************************************** /*****************************************************************************
* Local Prototypes * Local Prototypes
*****************************************************************************/ *****************************************************************************/
static void EmptyRelease( update_t *p_update );
static void GetUpdateFile( update_t *p_update );
static int cmp( int i1, int i2 );
static int CompareReleases( const struct update_release_t *p1,
const struct update_release_t *p2 );
static void FreeMirrorsList( update_t * );
static void FreeReleasesList( update_t * );
static void GetMirrorsList( update_t *, vlc_bool_t );
static void GetFilesList( update_t *, vlc_bool_t );
static int CompareReleases( const struct update_release_t *,
const struct update_release_t * );
static int CompareReleaseToCurrent( const struct update_release_t * );
static unsigned int update_iterator_Reset( update_iterator_t * );
static unsigned int update_iterator_NextFile( update_iterator_t * );
static unsigned int update_iterator_PrevFile( update_iterator_t * );
static unsigned int update_iterator_NextMirror( update_iterator_t * );
static unsigned int update_iterator_PrevMirror( update_iterator_t * );
static void update_iterator_GetData( update_iterator_t * );
static void update_iterator_ClearData( update_iterator_t * );
/***************************************************************************** /*****************************************************************************
* Update_t functions * Update_t functions
...@@ -128,22 +102,12 @@ update_t *__update_New( vlc_object_t *p_this ) ...@@ -128,22 +102,12 @@ update_t *__update_New( vlc_object_t *p_this )
p_update->p_libvlc = p_this->p_libvlc; p_update->p_libvlc = p_this->p_libvlc;
p_update->p_releases = NULL; p_update->release.psz_svnrev = NULL;
p_update->i_releases = 0; p_update->release.psz_extra = NULL;
p_update->b_releases = VLC_FALSE; p_update->release.psz_url = NULL;
p_update->release.psz_desc = NULL;
p_update->p_mirrors = NULL; return p_update;
p_update->i_mirrors = 0;
p_update->b_mirrors = VLC_FALSE;
#if 1
msg_Err( p_this, "Auto-update currently disabled." );
vlc_mutex_destroy( &p_update->lock );
free( p_update );
return NULL;
#else
return p_update
#endif
} }
/** /**
...@@ -157,284 +121,90 @@ void update_Delete( update_t *p_update ) ...@@ -157,284 +121,90 @@ void update_Delete( update_t *p_update )
assert( p_update ); assert( p_update );
vlc_mutex_destroy( &p_update->lock ); vlc_mutex_destroy( &p_update->lock );
FreeMirrorsList( p_update );
FreeReleasesList( p_update );
free( p_update );
}
/** if( p_update->release.psz_svnrev )
* Empty the mirrors list
* *p_update should be locked before using this function
*
* \param p_update pointer to the update struct
* \return nothing
*/
static void FreeMirrorsList( update_t *p_update )
{
int i;
for( i = 0; i < p_update->i_mirrors; i++ )
{ {
free( p_update->p_mirrors[i].psz_name ); free( p_update->release.psz_svnrev );
free( p_update->p_mirrors[i].psz_location ); p_update->release.psz_svnrev = NULL;
free( p_update->p_mirrors[i].psz_type );
free( p_update->p_mirrors[i].psz_base_url );
} }
FREENULL( p_update->p_mirrors );
p_update->i_mirrors = 0;
p_update->b_mirrors = VLC_FALSE;
}
/**
* Empty the releases list
* *p_update should be locked before calling this function
*
* \param p_update pointer to the update struct
* \return nothing
*/
static void FreeReleasesList( update_t *p_update )
{
int i;
for( i = 0; i < p_update->i_releases; i++ ) if( p_update->release.psz_extra )
{ {
int j; free( p_update->release.psz_extra );
struct update_release_t *p_release = (p_update->p_releases + i); p_update->release.psz_extra = NULL;
for( j = 0; j < p_release->i_files; j++ ) }
if( p_update->release.psz_url )
{ {
free( p_release->p_files[j].psz_md5 ); free( p_update->release.psz_url );
free( p_release->p_files[j].psz_url ); p_update->release.psz_url = NULL;
free( p_release->p_files[j].psz_description );
} }
free( p_release->psz_major );
free( p_release->psz_minor ); if( p_update->release.psz_desc )
free( p_release->psz_revision ); {
free( p_release->psz_extra ); free( p_update->release.psz_desc );
free( p_release->psz_svn_revision ); p_update->release.psz_desc = NULL;
free( p_release->p_files );
} }
FREENULL( p_update->p_releases );
p_update->i_releases = 0; free( p_update );
p_update->b_releases = VLC_FALSE;
} }
/** /**
* Get the mirrors list XML file and parse it * Empty the release struct
* *p_update has to be unlocked when calling this function
* *
* \param p_update pointer to the update struct * \param p_update update_t* pointer
* \param b_force set to VLC_TRUE if you want to force the mirrors list update
* \return nothing * \return nothing
*/ */
static void GetMirrorsList( update_t *p_update, vlc_bool_t b_force ) static void EmptyRelease( update_t *p_update )
{ {
stream_t *p_stream = NULL; p_update->release.i_major = 0;
p_update->release.i_minor = 0;
xml_t *p_xml = NULL; p_update->release.i_revision = 0;
xml_reader_t *p_xml_reader = NULL;
char *psz_eltname = NULL;
//char *psz_eltvalue = NULL;
char *psz_name = NULL;
char *psz_value = NULL;
struct update_mirror_t tmp_mirror;
vlc_mutex_lock( &p_update->lock );
memset( &tmp_mirror, 0, sizeof(struct update_mirror_t));
if( p_update->b_mirrors && b_force == VLC_FALSE )
{
vlc_mutex_unlock( &p_update->lock );
return;
}
p_xml = xml_Create( p_update->p_libvlc );
if( !p_xml )
{
msg_Err( p_update->p_libvlc, "Failed to open XML parser" );
goto error;
}
p_stream = stream_UrlNew( p_update->p_libvlc, UPDATE_VLC_MIRRORS_URL );
if( !p_stream )
{
msg_Err( p_update->p_libvlc, "Failed to open %s for reading",
UPDATE_VLC_MIRRORS_URL );
goto error;
}
p_xml_reader = xml_ReaderCreate( p_xml, p_stream );
if( !p_xml_reader )
{
msg_Err( p_update->p_libvlc, "Failed to open %s for parsing",
UPDATE_VLC_MIRRORS_URL );
goto error;
}
if( p_update->p_mirrors ) if( p_update->release.psz_svnrev )
{ {
FreeMirrorsList( p_update ); free( p_update->release.psz_svnrev );
p_update->release.psz_svnrev = NULL;
} }
while( xml_ReaderRead( p_xml_reader ) == 1 ) if( p_update->release.psz_extra )
{ {
switch( xml_ReaderNodeType( p_xml_reader ) ) free( p_update->release.psz_extra );
{ p_update->release.psz_extra = NULL;
case -1:
msg_Err( p_update->p_libvlc, "Error while parsing %s",
UPDATE_VLC_MIRRORS_URL );
goto error;
case XML_READER_STARTELEM:
psz_eltname = xml_ReaderName( p_xml_reader );
if( !psz_eltname )
{
msg_Err( p_update->p_libvlc, "Error while parsing %s",
UPDATE_VLC_MIRRORS_URL );
goto error;
} }
while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS ) if( p_update->release.psz_url )
{
psz_name = xml_ReaderName( p_xml_reader );
psz_value = xml_ReaderValue( p_xml_reader );
if( !psz_name || !psz_value )
{ {
msg_Err( p_update->p_libvlc, "Error while parsing %s", free( p_update->release.psz_url );
UPDATE_VLC_MIRRORS_URL ); p_update->release.psz_url = NULL;
goto error;
}
if( !strcmp( psz_eltname, "mirror" ) )
{
if( !strcmp( psz_name, "name" ) )
tmp_mirror.psz_name = STRDUP( psz_value );
else if( !strcmp( psz_name, "location" ) )
tmp_mirror.psz_location = STRDUP( psz_value );
}
else if( !strcmp( psz_eltname, "url" ) )
{
if( !strcmp( psz_name, "type" ) )
tmp_mirror.psz_type = STRDUP( psz_value );
else if( !strcmp( psz_name, "base" ) )
tmp_mirror.psz_base_url = STRDUP( psz_value );
}
FREENULL( psz_name );
FREENULL( psz_value );
}
if( !strcmp( psz_eltname, "url" ) )
{
/* append to mirrors list */
p_update->p_mirrors =
(struct update_mirror_t *)realloc( p_update->p_mirrors,
(++(p_update->i_mirrors))
*sizeof( struct update_mirror_t ) );
p_update->p_mirrors[ p_update->i_mirrors - 1 ] =
tmp_mirror;
tmp_mirror.psz_name = STRDUP( tmp_mirror.psz_name );
tmp_mirror.psz_location = STRDUP( tmp_mirror.psz_location );
tmp_mirror.psz_type = NULL;
tmp_mirror.psz_base_url = NULL;
}
FREENULL( psz_eltname );
break;
case XML_READER_ENDELEM:
psz_eltname = xml_ReaderName( p_xml_reader );
if( !psz_eltname )
{
msg_Err( p_update->p_libvlc, "Error while parsing %s",
UPDATE_VLC_MIRRORS_URL );
goto error;
} }
if( !strcmp( psz_eltname, "mirror" ) ) if( p_update->release.psz_desc )
{ {
FREENULL( tmp_mirror.psz_name ); free( p_update->release.psz_desc );
FREENULL( tmp_mirror.psz_location ); p_update->release.psz_desc = NULL;
} }
FREENULL( psz_eltname );
break;
/*case XML_READER_TEXT:
psz_eltvalue = xml_ReaderValue( p_xml_reader );
FREENULL( psz_eltvalue );
break;*/
}
}
p_update->b_mirrors = VLC_TRUE;
error:
vlc_mutex_unlock( &p_update->lock );
free( psz_eltname );
//free( psz_eltvalue );
free( psz_name );
free( psz_value );
free( tmp_mirror.psz_name );
free( tmp_mirror.psz_location );
free( tmp_mirror.psz_type );
free( tmp_mirror.psz_base_url );
if( p_xml_reader && p_xml )
xml_ReaderDelete( p_xml, p_xml_reader );
if( p_stream )
stream_Delete( p_stream );
if( p_xml )
xml_Delete( p_xml );
} }
/** /**
* Get the files list XML file and parse it * Get the update file and parse it
* *p_update has to be unlocked when calling this function * *p_update has to be unlocked when calling this function
* *
* \param p_update pointer to update struct * \param p_update pointer to update struct
* \param b_force set to VLC_TRUE if you want to force the files list update
* \return nothing * \return nothing
*/ */
static void GetFilesList( update_t *p_update, vlc_bool_t b_force ) static void GetUpdateFile( update_t *p_update )
{ {
stream_t *p_stream = NULL; stream_t *p_stream = NULL;
int i_major = 0;
xml_t *p_xml = NULL; int i_minor = 0;
xml_reader_t *p_xml_reader = NULL; int i_revision = 0;
char *psz_extra = NULL;
char *psz_eltname = NULL; char *psz_svnrev = NULL;
char *psz_eltvalue = NULL; char *psz_line = NULL;
char *psz_name = NULL;
char *psz_value = NULL;
struct update_release_t *p_release = NULL;
struct update_release_t tmp_release;
struct update_file_t tmp_file;
vlc_bool_t b_os = VLC_FALSE, b_arch = VLC_FALSE;
memset( &tmp_release, 0, sizeof(struct update_release_t) );
memset( &tmp_file, 0, sizeof(struct update_file_t) );
tmp_release.i_type = UPDATE_RELEASE_TYPE_STABLE;
vlc_mutex_lock( &p_update->lock ); vlc_mutex_lock( &p_update->lock );
if( p_update->b_releases && b_force == VLC_FALSE )
{
vlc_mutex_unlock( &p_update->lock );
return;
}
p_xml = xml_Create( p_update->p_libvlc );
if( !p_xml )
{
msg_Err( p_update->p_libvlc, "Failed to open XML parser" );
goto error;
}
p_stream = stream_UrlNew( p_update->p_libvlc, UPDATE_VLC_STATUS_URL ); p_stream = stream_UrlNew( p_update->p_libvlc, UPDATE_VLC_STATUS_URL );
if( !p_stream ) if( !p_stream )
{ {
...@@ -443,950 +213,171 @@ static void GetFilesList( update_t *p_update, vlc_bool_t b_force ) ...@@ -443,950 +213,171 @@ static void GetFilesList( update_t *p_update, vlc_bool_t b_force )
goto error; goto error;
} }
p_xml_reader = xml_ReaderCreate( p_xml, p_stream ); /* Try to read three lines */
if( !( psz_line = stream_ReadLine( p_stream ) ) )
if( !p_xml_reader )
{
msg_Err( p_update->p_libvlc, "Failed to open %s for parsing",
UPDATE_VLC_STATUS_URL );
goto error;
}
if( p_update->p_releases )
{
FreeReleasesList( p_update );
}
while( xml_ReaderRead( p_xml_reader ) == 1 )
{
switch( xml_ReaderNodeType( p_xml_reader ) )
{
case -1:
msg_Err( p_update->p_libvlc, "Error while parsing %s",
UPDATE_VLC_STATUS_URL );
goto error;
case XML_READER_STARTELEM:
psz_eltname = xml_ReaderName( p_xml_reader );
if( !psz_eltname )
{ {
msg_Err( p_update->p_libvlc, "Error while parsing %s", msg_Err( p_update->p_libvlc, "Update file %s is corrupted : missing version",
UPDATE_VLC_STATUS_URL ); UPDATE_VLC_STATUS_URL );
goto error; goto error;
} }
while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS ) /* first line : version number */
if( sscanf( psz_line, "%i.%i.%i%as %as", &i_major, &i_minor, &i_revision, &psz_extra, &psz_svnrev ) )
{ {
psz_name = xml_ReaderName( p_xml_reader ); p_update->release.i_major = i_major;
psz_value = xml_ReaderValue( p_xml_reader ); p_update->release.i_minor = i_minor;
p_update->release.i_revision = i_revision;
if( !psz_name || !psz_value ) if( psz_svnrev )
{ p_update->release.psz_svnrev = psz_svnrev;
msg_Err( p_update->p_libvlc, "Error while parsing %s",
UPDATE_VLC_STATUS_URL );
goto error;
}
if( b_os && b_arch )
{
if( strcmp( psz_eltname, "version" ) == 0 )
{
if( !strcmp( psz_name, "major" ) )
tmp_release.psz_major = STRDUP( psz_value );
else if( !strcmp( psz_name, "minor" ) )
tmp_release.psz_minor = STRDUP( psz_value );
else if( !strcmp( psz_name, "revision" ) )
tmp_release.psz_revision = STRDUP( psz_value );
else if( !strcmp( psz_name, "extra" ) )
tmp_release.psz_extra = STRDUP( psz_value );
else if( !strcmp( psz_name, "svn" ) )
tmp_release.psz_svn_revision =
STRDUP( psz_value );
else if( !strcmp( psz_name, "version" ) )
{
if( !strcmp( psz_value, "unstable" ) )
tmp_release.i_type =
UPDATE_RELEASE_TYPE_UNSTABLE;
else if( !strcmp( psz_value, "testing" ) )
tmp_release.i_type =
UPDATE_RELEASE_TYPE_TESTING;
else else
tmp_release.i_type = p_update->release.psz_svnrev = STRDUP( "" );
UPDATE_RELEASE_TYPE_STABLE;
} if( psz_extra )
} p_update->release.psz_extra = psz_extra;
else if( !strcmp( psz_eltname, "file" ) )
{
if( !strcmp( psz_name, "type" ) )
{
if( !strcmp( psz_value, "info" ) )
tmp_file.i_type = UPDATE_FILE_TYPE_INFO;
else if( !strcmp( psz_value, "source" ) )
tmp_file.i_type = UPDATE_FILE_TYPE_SOURCE;
else if( !strcmp( psz_value, "binary" ) )
tmp_file.i_type = UPDATE_FILE_TYPE_BINARY;
else if( !strcmp( psz_value, "plugin" ) )
tmp_file.i_type = UPDATE_FILE_TYPE_PLUGIN;
else else
tmp_file.i_type = UPDATE_FILE_TYPE_UNDEF; p_update->release.psz_extra = STRDUP( "" );
}
else if( !strcmp( psz_name, "md5" ) )
tmp_file.psz_md5 = STRDUP( psz_value );
else if( !strcmp( psz_name, "size" ) )
tmp_file.l_size = atol( psz_value );
else if( !strcmp( psz_name, "url" ) )
tmp_file.psz_url = STRDUP( psz_value );
}
}
if( !strcmp( psz_name, "name" )
&& ( !strcmp( psz_value, UPDATE_VLC_OS )
|| !strcmp( psz_value, "*" ) )
&& !strcmp( psz_eltname, "os" ) )
{
b_os = VLC_TRUE;
}
if( b_os && !strcmp( psz_name, "name" )
&& ( !strcmp( psz_value, UPDATE_VLC_ARCH )
|| !strcmp( psz_value, "*" ) )
&& !strcmp( psz_eltname, "arch" ) )
{
b_arch = VLC_TRUE;
}
FREENULL( psz_name );
FREENULL( psz_value );
}
if( ( b_os && b_arch && strcmp( psz_eltname, "arch" ) ) )
{
if( !strcmp( psz_eltname, "version" ) )
{
int i;
/* look for a previous occurrence of this release */
for( i = 0; i < p_update->i_releases; i++ )
{
p_release = p_update->p_releases + i;
if( CompareReleases( p_release, &tmp_release )
== UPDATE_RELEASE_STATUS_EQUAL )
{
break;
}
}
/* if this is the first time that we see this release,
* append it to the list of releases */
if( i == p_update->i_releases )
{
tmp_release.i_status =
CompareReleaseToCurrent( &tmp_release );
p_update->p_releases =
(struct update_release_t *)realloc( p_update->p_releases,
(++(p_update->i_releases))*sizeof( struct update_release_t ) );
p_update->p_releases[ p_update->i_releases - 1 ] =
tmp_release;
p_release =
p_update->p_releases + p_update->i_releases - 1;
tmp_release.psz_major = NULL;
tmp_release.psz_minor = NULL;
tmp_release.psz_revision = NULL;
tmp_release.psz_extra = NULL;
tmp_release.psz_svn_revision = NULL;
tmp_release.i_type = UPDATE_RELEASE_TYPE_STABLE;
tmp_release.i_status = 0;
tmp_release.p_files = NULL;
tmp_release.i_files = 0;
} }
else else
{ {
FREENULL( tmp_release.psz_major ); msg_Err( p_update->p_libvlc, "Update version false formated" );
FREENULL( tmp_release.psz_minor ); free( psz_line );
FREENULL( tmp_release.psz_revision );
FREENULL( tmp_release.psz_extra );
FREENULL( tmp_release.psz_svn_revision );
tmp_release.i_type = UPDATE_RELEASE_TYPE_STABLE;
FREENULL( tmp_release.p_files );
tmp_release.i_files = 0;
}
}
else if( !strcmp( psz_eltname, "file" ) )
{
/* append file to p_release's file list */
if( p_release == NULL )
{
goto error; goto error;
} }
p_release->p_files =
(struct update_file_t *)realloc( p_release->p_files,
(++(p_release->i_files))*sizeof( struct update_file_t ) );
p_release->p_files[ p_release->i_files - 1 ] = tmp_file;
tmp_file.i_type = UPDATE_FILE_TYPE_UNDEF;
tmp_file.psz_md5 = NULL;
tmp_file.l_size = 0;
tmp_file.psz_url = NULL;
tmp_file.psz_description = NULL;
}
}
FREENULL( psz_eltname );
break;
case XML_READER_ENDELEM: /* Second line : URL */
psz_eltname = xml_ReaderName( p_xml_reader ); if( !( psz_line = stream_ReadLine( p_stream ) ) )
if( !psz_eltname )
{ {
msg_Err( p_update->p_libvlc, "Error while parsing %s", msg_Err( p_update->p_libvlc, "Update file %s is corrupted : URL missing",
UPDATE_VLC_STATUS_URL ); UPDATE_VLC_STATUS_URL );
goto error; goto error;
} }
p_update->release.psz_url = psz_line;
if( !strcmp( psz_eltname, "os" ) )
b_os = VLC_FALSE;
else if( !strcmp( psz_eltname, "arch" ) )
b_arch = VLC_FALSE;
FREENULL( psz_eltname );
break;
case XML_READER_TEXT: /* Third line : description */
psz_eltvalue = xml_ReaderValue( p_xml_reader ); if( !( psz_line = stream_ReadLine( p_stream ) ) )
if( p_release && p_release->i_files ) {
p_release->p_files[ p_release->i_files - 1 ] msg_Err( p_update->p_libvlc, "Update file %s is corrupted : description missing",
.psz_description = STRDUP( psz_eltvalue ); UPDATE_VLC_STATUS_URL );
FREENULL( psz_eltvalue ); goto error;
break;
}
} }
p_update->release.psz_desc = psz_line;
p_update->b_releases = VLC_TRUE;
error: error:
vlc_mutex_unlock( &p_update->lock ); vlc_mutex_unlock( &p_update->lock );
free( psz_eltname );
free( psz_eltvalue );
free( psz_name );
free( psz_value );
free( tmp_release.psz_major );
free( tmp_release.psz_minor );
free( tmp_release.psz_revision );
free( tmp_release.psz_extra );
free( tmp_release.psz_svn_revision );
free( tmp_file.psz_md5 );
free( tmp_file.psz_url );
free( tmp_file.psz_description );
if( p_xml_reader && p_xml )
xml_ReaderDelete( p_xml, p_xml_reader );
if( p_stream ) if( p_stream )
stream_Delete( p_stream ); stream_Delete( p_stream );
if( p_xml )
xml_Delete( p_xml );
} }
/** /**
* Check for updates * Check for updates
* *
* \param p_update pointer to update struct * \param p_update pointer to update struct
* \param b_force set to VLC_TRUE if you want to force the update
* \returns nothing * \returns nothing
*/ */
void update_Check( update_t *p_update, vlc_bool_t b_force ) void update_Check( update_t *p_update )
{ {
assert( p_update ); assert( p_update );
GetMirrorsList( p_update, b_force ); EmptyRelease( p_update );
GetFilesList( p_update, b_force );
}
/**
* Compare two release numbers
* The comparision algorith basically performs an alphabetical order (strcmp)
* comparision of each of the version number elements until it finds two
* different ones. This is the tricky function.
*
* \param p1 first release
* \param p2 second release
* \return like strcmp
*/
static int CompareReleases( const struct update_release_t *p1,
const struct update_release_t *p2 )
{
int d;
if( ( d = strcmp( p1->psz_major, p2->psz_major ) ) ) ;
else if( ( d = strcmp( p1->psz_minor, p2->psz_minor ) ) ) ;
else if( ( d = strcmp( p1->psz_revision, p2->psz_revision ) ) ) ;
else
{
d = strcmp( p1->psz_extra, p2->psz_extra );
if( d<0 )
{
/* FIXME:
* not num < NULL < num
* -test and -svn releases are thus always considered older than
* -'' or -0 releases, which is the best i could come up with */
char *psz_end1;
char *psz_end2;
strtol( p1->psz_extra, &psz_end1, 10 );
strtol( p2->psz_extra, &psz_end2, 10 );
if( psz_end2 == p2->psz_extra
&& ( psz_end1 != p1->psz_extra || *p1->psz_extra == '\0' ) )
d = 1;
}
}
if( d < 0 )
return UPDATE_RELEASE_STATUS_OLDER;
else if( d == 0 )
return UPDATE_RELEASE_STATUS_EQUAL;
else
return UPDATE_RELEASE_STATUS_NEWER;
}
/**
* Compare a given release's version number to the current VLC's one
*
* \param p a release
* \return >0 if newer, 0 if equal and <0 if older
*/
static int CompareReleaseToCurrent( const struct update_release_t *p )
{
struct update_release_t c;
int r;
memset( &c, 0, sizeof(struct update_release_t) );
c.psz_major = STRDUP( PACKAGE_VERSION_MAJOR );
c.psz_minor = STRDUP( PACKAGE_VERSION_MINOR );
c.psz_revision = STRDUP( PACKAGE_VERSION_REVISION );
c.psz_extra = STRDUP( PACKAGE_VERSION_EXTRA );
r = CompareReleases( p, &c );
free( c.psz_major );
free( c.psz_minor );
free( c.psz_revision );
free( c.psz_extra );
return r;
}
/*****************************************************************************
* Updatei_iterator_t functions
*****************************************************************************/
/**
* Create a new update iterator structure. This structure can then be used to
* describe a position and move through the update and mirror trees/lists.
* This will use an existing update struct or create a new one if none is
* found
*
* \param p_u the calling update_t
* \return a pointer to an update iterator
*/
update_iterator_t *update_iterator_New( update_t *p_u )
{
update_iterator_t *p_uit = NULL;
assert( p_u );
p_uit = (update_iterator_t *)malloc( sizeof( update_iterator_t ) );
if( p_uit == NULL ) return NULL;
p_uit->p_u = p_u;
p_uit->i_m = -1;
p_uit->i_r = -1;
p_uit->i_f = -1;
p_uit->i_t = UPDATE_FILE_TYPE_ALL;
p_uit->i_rs = UPDATE_RELEASE_STATUS_ALL;
p_uit->i_rt = UPDATE_RELEASE_TYPE_STABLE;
p_uit->file.i_type = UPDATE_FILE_TYPE_NONE;
p_uit->file.psz_md5 = NULL;
p_uit->file.psz_url = NULL;
p_uit->file.l_size = 0;
p_uit->file.psz_description = NULL;
p_uit->release.psz_version = NULL;
p_uit->release.psz_svn_revision = NULL;
p_uit->release.i_type = UPDATE_RELEASE_TYPE_UNSTABLE;
p_uit->release.i_status = UPDATE_RELEASE_STATUS_NONE;
p_uit->mirror.psz_name = NULL;
p_uit->mirror.psz_location = NULL;
p_uit->mirror.psz_type = NULL;
return p_uit; GetUpdateFile( p_update );
} }
/** /**
* Delete an update iterator structure (duh!) * Compare two integers
* *
* \param p_uit pointer to an update iterator * \param p1 first integer
* \return nothing * \param p2 second integer
*/ * \return like strcmp
void update_iterator_Delete( update_iterator_t *p_uit )
{
assert( p_uit );
update_iterator_ClearData( p_uit );
free( p_uit );
}
/**
* Reset an update_iterator_t structure
*
* \param p_uit pointer to an update iterator
* \return UPDATE_FAIL upon error, UPDATE_SUCCESS otherwise
*/
unsigned int update_iterator_Reset( update_iterator_t *p_uit )
{
assert( p_uit );
p_uit->i_r = -1;
p_uit->i_f = -1;
p_uit->i_m = -1;
update_iterator_ClearData( p_uit );
return UPDATE_SUCCESS;
}
/**
* Finds the next file in the update tree that matches status and type
* requirements set in the update_iterator
*
* \param p_uit update iterator
* \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
*/
static unsigned int update_iterator_NextFile( update_iterator_t *p_uit )
{
int r,f=-1,old_r;
assert( p_uit );
old_r=p_uit->i_r;
/* if the update iterator was already in a "no match" state, start over */
if( p_uit->i_r == -1 ) p_uit->i_r = 0;
//if( p_uit->i_f == -1 ) p_uit->i_f = 0;
vlc_mutex_lock( &p_uit->p_u->lock );
for( r = p_uit->i_r; r < p_uit->p_u->i_releases; r++ )
{
if( !( p_uit->p_u->p_releases[r].i_status & p_uit->i_rs ) ) continue;
for( f = ( r == p_uit->i_r ? p_uit->i_f + 1 : 0 );
f < p_uit->p_u->p_releases[r].i_files; f++ )
{
if( p_uit->p_u->p_releases[r].p_files[f].i_type & p_uit->i_t )
{
goto done;/* "double break" */
}
}
}
done:
p_uit->i_r = r;
p_uit->i_f = f;
r = p_uit->p_u->i_releases;
if( old_r == p_uit->i_r )
{
update_iterator_GetData( p_uit );
vlc_mutex_unlock( &p_uit->p_u->lock );
return UPDATE_SUCCESS|UPDATE_FILE;
}
else if( p_uit->i_r == r )
{
p_uit->i_r = -1;
p_uit->i_f = -1;
update_iterator_GetData( p_uit );
vlc_mutex_unlock( &p_uit->p_u->lock );
return UPDATE_FAIL;
}
else
{
update_iterator_GetData( p_uit );
vlc_mutex_unlock( &p_uit->p_u->lock );
return UPDATE_SUCCESS|UPDATE_RELEASE|UPDATE_FILE;
}
}
/**
* Finds the previous file in the update tree that matches status and type
* requirements set in the update_iterator
*
* \param p_uit update iterator
* \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
*/
//TODO: test
static unsigned int update_iterator_PrevFile( update_iterator_t *p_uit )
{
int r,f=-1,old_r;
if( !p_uit ) return UPDATE_FAIL;
old_r=p_uit->i_r;
/* if the update iterator was already in a "no match" state, start over
* (begin at the end of the list) */
if( p_uit->i_r == -1 ) p_uit->i_r = p_uit->p_u->i_releases - 1;
p_uit->i_f = p_uit->p_u->p_releases[p_uit->i_r].i_files + 1;
vlc_mutex_lock( &p_uit->p_u->lock );
for( r = p_uit->i_r; r >= 0; r-- )
{
if( !( p_uit->p_u->p_releases[r].i_status & p_uit->i_rs ) ) continue;
for( f =( r==p_uit->i_r ? p_uit->i_f - 1 : p_uit->p_u->p_releases[r].i_files );
f >= 0; f-- )
{
if( p_uit->p_u->p_releases[r].p_files[f].i_type & p_uit->i_t )
{
goto done;/* "double break" */
}
}
}
done:
p_uit->i_r = r;
p_uit->i_f = f;
r = p_uit->p_u->i_releases;
if( old_r == p_uit->i_r )
{
update_iterator_GetData( p_uit );
vlc_mutex_unlock( &p_uit->p_u->lock );
return UPDATE_SUCCESS|UPDATE_FILE;
}
else if( p_uit->i_r == -1 )
{
p_uit->i_r = -1;
p_uit->i_f = -1;
update_iterator_GetData( p_uit );
vlc_mutex_unlock( &p_uit->p_u->lock );
return UPDATE_FAIL;
}
else
{
update_iterator_GetData( p_uit );
vlc_mutex_unlock( &p_uit->p_u->lock );
return UPDATE_SUCCESS|UPDATE_RELEASE|UPDATE_FILE;
}
}
/**
* Finds the next mirror in the update tree
*
* \param update iterator
* \return UPDATE_FAIL if we can't find the next mirror, UPDATE_SUCCESS|UPDATE_MIRROR otherwise
*/
static unsigned int update_iterator_NextMirror( update_iterator_t *p_uit )
{
if( !p_uit ) return UPDATE_FAIL;
vlc_mutex_lock( &p_uit->p_u->lock );
p_uit->i_m++;
if( p_uit->i_m >= p_uit->p_u->i_mirrors ) p_uit->i_m = -1;
update_iterator_GetData( p_uit );
vlc_mutex_unlock( &p_uit->p_u->lock );
return p_uit->i_m == -1 ? UPDATE_FAIL : UPDATE_SUCCESS|UPDATE_MIRROR;
}
/**
* Finds the previous mirror in the update tree
*
* \param update iterator
* \return UPDATE_FAIL if we can't find a previous mirror, UPDATE_SUCCESS|UPDATE_MIRROR otherwise
*/
static unsigned int update_iterator_PrevMirror( update_iterator_t *p_uit )
{
if( !p_uit ) return UPDATE_FAIL;
vlc_mutex_lock( &p_uit->p_u->lock );
p_uit->i_m--;
update_iterator_GetData( p_uit );
vlc_mutex_unlock( &p_uit->p_u->lock );
return p_uit->i_m == -1 ? UPDATE_FAIL : UPDATE_SUCCESS|UPDATE_MIRROR;
}
/**
* Change the update iterator's position in the file and mirrors tree
* If position is negative, don't change it
*
* \param i_m position in mirrors list
* \param i_r position in releases list
* \param i_f position in release's files list
* \return UPDATE_FAIL when changing position fails or position wasn't changed, a combination of UPDATE_MIRROR, UPDATE_RELEASE and UPDATE_FILE otherwise
*/
unsigned int update_iterator_ChooseMirrorAndFile( update_iterator_t *p_uit,
int i_m, int i_r, int i_f )
{
unsigned int i_val = 0;
if( !p_uit ) return 0;
vlc_mutex_lock( &p_uit->p_u->lock );
if( i_m >= 0 )
{
if( i_m < p_uit->p_u->i_mirrors )
{
if( i_m != p_uit->i_m )
i_val |= UPDATE_MIRROR;
p_uit->i_m = i_m;
}
else i_m = -1;
}
if( i_r >= 0 )
{
if( i_r < p_uit->p_u->i_releases )
{
if( i_r != p_uit->i_r )
i_val |= UPDATE_FILE;
p_uit->i_r = i_r;
}
else i_r = -1;
}
if( i_f >= 0 )
{
if( i_r >= 0 && i_r < p_uit->p_u->i_releases
&& i_f < p_uit->p_u->p_releases[p_uit->i_r].i_files )
{
if( i_f != p_uit->i_f )
i_val |= UPDATE_FILE;
p_uit->i_f = i_f;
}
else i_f = -1;
}
update_iterator_GetData( p_uit );
vlc_mutex_unlock( &p_uit->p_u->lock );
if( ( i_m < 0 || p_uit->i_m >= 0 )
&& ( i_r < 0 || p_uit->i_r >= 0 )
&& ( i_f < 0 || p_uit->i_f >= 0 ) )
{
/* Everything worked */
return UPDATE_SUCCESS|i_val;
}
else
{
/* Something failed */
return UPDATE_FAIL;
}
}
/**
* Fills the iterator data (file, release and mirror structs)
* The update struct should be locked before calling this function.
*
* \param p_uit update iterator
* \return nothing
*/ */
static void update_iterator_GetData( update_iterator_t *p_uit ) static int cmp( int i1, int i2 )
{ {
struct update_release_t *p_r = NULL; if( i1 < i2 )
struct update_file_t *p_f = NULL; return -1;
struct update_mirror_t *p_m = NULL; else if(i1 == i2)
return 0;
update_iterator_ClearData( p_uit );
if( p_uit->i_m >= 0 )
{
p_m = p_uit->p_u->p_mirrors + p_uit->i_m;
p_uit->mirror.psz_name = STRDUP( p_m->psz_name );
p_uit->mirror.psz_location = STRDUP( p_m->psz_location );
p_uit->mirror.psz_type = STRDUP( p_m->psz_type );
}
if( p_uit->i_r >= 0 )
{
p_r = p_uit->p_u->p_releases + p_uit->i_r;
asprintf( &p_uit->release.psz_version, "%s.%s.%s-%s",
p_r->psz_major,
p_r->psz_minor,
p_r->psz_revision,
p_r->psz_extra );
p_uit->release.psz_svn_revision = STRDUP( p_r->psz_svn_revision );
p_uit->release.i_type = p_r->i_type;
p_uit->release.i_status = p_r->i_status;
if( p_uit->i_f >= 0 )
{
p_f = p_r->p_files + p_uit->i_f;
p_uit->file.i_type = p_f->i_type;
p_uit->file.psz_md5 = STRDUP( p_f->psz_md5 );
p_uit->file.l_size = p_f->l_size;
p_uit->file.psz_description = STRDUP( p_f->psz_description);
if( p_f->psz_url[0] == '/' )
{
if( p_m )
{
asprintf( &p_uit->file.psz_url, "%s%s",
p_m->psz_base_url, p_f->psz_url );
}
}
else else
{ return 1;
p_uit->file.psz_url = STRDUP( p_f->psz_url );
}
}
}
} }
/** /**
* Clears the iterator data (file, release and mirror structs) * Compare two release numbers
*
* \param p_uit update iterator
* \return nothing
*/
static void update_iterator_ClearData( update_iterator_t *p_uit )
{
p_uit->file.i_type = UPDATE_FILE_TYPE_NONE;
FREENULL( p_uit->file.psz_md5 );
p_uit->file.l_size = 0;
FREENULL( p_uit->file.psz_description );
FREENULL( p_uit->file.psz_url );
FREENULL( p_uit->release.psz_version );
FREENULL( p_uit->release.psz_svn_revision );
p_uit->release.i_type = UPDATE_RELEASE_TYPE_UNSTABLE;
p_uit->release.i_status = UPDATE_RELEASE_STATUS_NONE;
FREENULL( p_uit->mirror.psz_name );
FREENULL( p_uit->mirror.psz_location );
FREENULL( p_uit->mirror.psz_type );
}
/**
* Perform an action on the update iterator
* Only the first matching action is performed.
* *
* \param p_uit update iterator * \param p1 first release
* \param i_action update action bitmask. can be a combination of UPDATE_NEXT, UPDATE_PREV, UPDATE_MIRROR, UPDATE_RELEASE, UPDATE_FILE, UPDATE_RESET * \param p2 second release
* \return UPDATE_FAIL if action fails, UPDATE_SUCCESS|(combination of UPDATE_MIRROR, UPDATE_RELEASE and UPDATE_FILE if these changed) otherwise * \return UpdateReleaseStatus(Older|Equal|Newer)
*/ */
unsigned int update_iterator_Action( update_iterator_t *p_uit, int i_action ) static int CompareReleases( const struct update_release_t *p1,
const struct update_release_t *p2 )
{ {
if( i_action & UPDATE_RESET ) int d;
{ if( ( d = cmp( p1->i_major, p2->i_major ) ) ) ;
return update_iterator_Reset( p_uit ); else if( ( d = cmp( p1->i_minor, p2->i_minor ) ) ) ;
} else if( ( d = cmp( p1->i_revision, p2->i_revision ) ) ) ;
else else
if( i_action & UPDATE_MIRROR )
{ {
if( i_action & UPDATE_PREV ) if( p1->psz_extra[0] == '-' )
{ {
return update_iterator_PrevMirror( p_uit ); if( p2->psz_extra[0] == '-' )
} d = strcmp( p1->psz_extra, p2->psz_extra );
else else
{ d = 1;
return update_iterator_NextMirror( p_uit );
}
}
/*else if( i_action & UPDATE_RELEASE )
{
if( i_action & UPDATE_PREV )
{
return update_iterator_PrevRelease( p_uit );
} }
else else
{ {
return update_iterator_NextRelease( p_uit ); if( p2->psz_extra[0] == '-' )
} d = -1;
}*/
else if( i_action & UPDATE_FILE )
{
if( i_action & UPDATE_PREV )
{
return update_iterator_PrevFile( p_uit );
}
else else
{ d = strcmp(p1->psz_extra, p2->psz_extra );
return update_iterator_NextFile( p_uit );
} }
if( d == 0 )
d = strcmp( p1->psz_svnrev, p2->psz_svnrev );
} }
else
{
return UPDATE_SUCCESS;
}
}
/**
* Object to launch download thread in a different object
*/
typedef struct {
VLC_COMMON_MEMBERS
char *psz_dest; //< Download destination
struct update_file_t src; //< Download source
char *psz_status; //< Download status displayed in progress dialog
} download_thread_t;
void update_download_for_real( download_thread_t *p_this );
/** if( d < 0 )
* Download the file selected by the update iterator. This function will return UpdateReleaseStatusOlder;
* launch the download in a new thread (downloads can be long) else if( d == 0 )
* return UpdateReleaseStatusEqual;
* \param p_uit update iterator
* \param psz_dest destination file path
* \return nothing
*/
void update_download( update_iterator_t *p_uit, const char *psz_dest )
{
download_thread_t *p_dt =
vlc_object_create( p_uit->p_u->p_libvlc, sizeof( download_thread_t ) );
p_dt->psz_dest = strdup( psz_dest );
p_dt->src.i_type = p_uit->file.i_type;
p_dt->src.l_size = p_uit->file.l_size;
p_dt->src.psz_md5 = STRDUP( p_uit->file.psz_md5 );
p_dt->src.psz_url = STRDUP( p_uit->file.psz_url );
p_dt->src.psz_description = STRDUP( p_uit->file.psz_description );
asprintf( &p_dt->psz_status, "%s - %s (%s)\nSource: %s\nDestination: %s",
p_uit->file.psz_description, p_uit->release.psz_version,
p_uit->release.psz_svn_revision, p_uit->file.psz_url,
psz_dest);
vlc_thread_create( p_dt, "download thread", update_download_for_real,
VLC_THREAD_PRIORITY_LOW, VLC_FALSE );
}
/**
* Convert a long int size in bytes to a string
*
* \param l_size the size in bytes
* \return the size as a string
*/
static char *size_str( long int l_size )
{
char *psz_tmp;
if( l_size>> 30 )
asprintf( &psz_tmp, "%.1f GB", (float)l_size/(1<<30) );
if( l_size >> 20 )
asprintf( &psz_tmp, "%.1f MB", (float)l_size/(1<<20) );
else if( l_size >> 10 )
asprintf( &psz_tmp, "%.1f kB", (float)l_size/(1<<10) );
else else
asprintf( &psz_tmp, "%ld B", l_size ); return UpdateReleaseStatusNewer;
return psz_tmp;
} }
/** /**
* The true download function. * Compare a given release's version number to the current VLC's one
* *
* \param p_this the download_thread_t object * \param p a release
* \return nothing * \return UpdateReleaseStatus(Older|Equal|Newer)
*/ */
void update_download_for_real( download_thread_t *p_this ) int update_CompareReleaseToCurrent( update_t *p_update )
{ {
char *psz_dest = p_this->psz_dest; assert( p_update );
char *psz_src = p_this->src.psz_url;
stream_t *p_stream;
libvlc_int_t *p_libvlc = p_this->p_libvlc;
FILE *p_file = NULL;
void *p_buffer;
char *psz_status;
int i_progress;
long int l_size, l_done = 0;
vlc_thread_ready( p_this );
asprintf( &psz_status, "%s\nDownloading... 0.0/? %.1f%% done",
p_this->psz_status, 0.0 );
i_progress = intf_UserProgress( p_libvlc, "Downloading...",
psz_status, 0.0, 0 );
p_stream = stream_UrlNew( p_libvlc, psz_src ); struct update_release_t c;
if( !p_stream ) int i_major = 0;
{ int i_minor = 0;
msg_Err( p_libvlc, "Failed to open %s for reading", psz_src ); int i_revision = 0;
intf_UserFatal( p_libvlc, VLC_TRUE, "Download Error", char *psz_extra;
"VLC failed to open %s for reading.", psz_src ); int i_result = UpdateReleaseStatusOlder;
intf_UserHide( p_libvlc, i_progress );
} /* get the current version number */
else if( sscanf( PACKAGE_VERSION, "%i.%i.%i%as", &i_major, &i_minor, &i_revision, &psz_extra ) )
{ {
l_size = stream_Size(p_stream); c.i_major = i_major;
if( l_size != p_this->src.l_size ) c.i_minor = i_minor;
{ c.i_revision = i_revision;
stream_Delete( p_stream ); if( psz_extra )
free( psz_status ); c.psz_extra = psz_extra;
msg_Err( p_this, "%s hasn't a correct size (%li instead of %li)."
" Cancelling download.",
p_this->src.psz_description,
l_size,
p_this->src.l_size );
goto end;
}
p_file = utf8_fopen( psz_dest, "w" );
if( !p_file )
{
msg_Err( p_libvlc, "Failed to open %s for writing", psz_dest );
intf_UserFatal( p_libvlc, VLC_TRUE, "Download Error",
"VLC failed to open %s for writing.", psz_dest );
intf_UserHide( p_libvlc, i_progress );
}
else else
{ c.psz_extra = STRDUP( "" );
int i_read; c.psz_svnrev = STRDUP( VLC_Changeset() );
char *psz_s1; char *psz_s2;
struct md5_s md5_s;
p_buffer = (void *)malloc( 1<<10 );
if( p_buffer )
{
if( p_this->src.i_type & ( UPDATE_FILE_TYPE_SOURCE | UPDATE_FILE_TYPE_BINARY | UPDATE_FILE_TYPE_PLUGIN ) )
InitMD5( &md5_s );
while( ( i_read = stream_Read( p_stream, p_buffer, 1<<10 ) ) )
{
float f_progress;
fwrite( p_buffer, i_read, 1, p_file );
if( p_this->src.i_type & ( UPDATE_FILE_TYPE_SOURCE | UPDATE_FILE_TYPE_BINARY | UPDATE_FILE_TYPE_PLUGIN ) )
AddMD5( &md5_s, p_buffer, (size_t) i_read );
l_done += i_read; i_result = CompareReleases( &p_update->release, &c );
free( psz_status );
f_progress = 100.0*(float)l_done/(float)l_size;
psz_s1 = size_str( l_done );
psz_s2 = size_str( l_size );
asprintf( &psz_status, "%s\nDownloading... %s/%s (%.1f%%) done",
p_this->psz_status, psz_s1, psz_s2, f_progress );
free( psz_s1 );
free( psz_s2 );
intf_ProgressUpdate( p_libvlc, i_progress, free( c.psz_extra );
psz_status, f_progress, 0 ); free( c.psz_svnrev );
}
free( p_buffer );
}
fclose( p_file );
stream_Delete( p_stream );
if( l_done == p_this->src.l_size &&
p_this->src.i_type & ( UPDATE_FILE_TYPE_SOURCE |
UPDATE_FILE_TYPE_BINARY | UPDATE_FILE_TYPE_PLUGIN ) )
{
EndMD5( &md5_s );
char *psz_md5 = psz_md5_hash( &md5_s );
if( !p_this->src.psz_md5 || !psz_md5 ||
strncmp( psz_md5, p_this->src.psz_md5, 32 ) )
{
msg_Err( p_this, _("%s has an incorrect checksum, download failed or mirror is compromised.\n Please run an antivirus on %s, and report if that file is trojaned.\n If not, please try later."),
p_this->src.psz_description, psz_dest );
}
free( psz_md5 );
}
free( psz_status );
psz_s2 = size_str( l_size );
asprintf( &psz_status, "%s\nDone %s (100.00%%)",
p_this->psz_status, psz_s2 );
free( psz_s2 );
intf_ProgressUpdate( p_libvlc, i_progress, psz_status, 100.0, 0 );
free( psz_status );
}
} }
return i_result;
end:
free( p_this->psz_dest );
free( p_this->src.psz_url );
free( p_this->src.psz_description );
free( p_this->src.psz_md5 );
free( p_this->psz_status );
vlc_object_destroy( p_this );
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment