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 @@
* @{
*/
#define UPDATE_FILE_TYPE_ALL (~0)
#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
enum
{
int i_type; ///< File type
char* psz_md5; ///< MD5 hash
long int l_size; ///< File size in bytes
char* psz_url; ///< Relative (to a mirror) or absolute url
char* psz_description; ///< Plain text description
UpdateReleaseStatusOlder,
UpdateReleaseStatusEqual,
UpdateReleaseStatusNewer
};
/**
......@@ -82,32 +48,13 @@ struct update_file_t
*/
struct update_release_t
{
char* psz_major; ///< Version major string
char* psz_minor; ///< Version minor string
char* psz_revision; ///< Version revision string
char* psz_extra; ///< Version extra string
char* psz_svn_revision; ///< SVN revision
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
int i_major; ///< Version major
int i_minor; ///< Version minor
int i_revision; ///< Version revision
char* psz_svnrev; ///< SVN revision
char* psz_extra; ///< Version extra
char* psz_url; ///< Download URL
char* psz_desc; ///< Release description
};
/**
......@@ -116,60 +63,17 @@ struct update_mirror_t
struct update_t
{
libvlc_int_t *p_libvlc;
vlc_mutex_t lock;
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
struct update_release_t release; ///< Release (version)
};
/**
* 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 ) )
VLC_EXPORT( update_t *, __update_New, ( vlc_object_t * ) );
VLC_EXPORT( void, update_Delete, (update_t * ) );
VLC_EXPORT( void, update_Check, ( update_t *, vlc_bool_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 * ) );
VLC_EXPORT( void, update_Delete, ( update_t * ) );
VLC_EXPORT( void, update_Check, ( update_t * ) );
VLC_EXPORT( int, update_CompareReleaseToCurrent, ( update_t * ) );
/**
* @}
......
......@@ -96,7 +96,7 @@ static int AudioConfig ( vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void * );
static int Menu ( vlc_object_t *, char const *,
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 */
static int TimeOffsetChanged( vlc_object_t *, char const *,
......@@ -752,7 +752,7 @@ static void Run( intf_thread_t *p_intf )
}
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" ) )
{
......@@ -2105,116 +2105,20 @@ static input_item_t *parse_MRL( intf_thread_t *p_intf, char *psz_mrl )
/*****************************************************************************
* 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 );
if( p_u == NULL ) return;
p_uit = update_iterator_New( p_u );
if( p_uit )
{
int s = 0, t = 0;
if( strstr( psz_arg, "newer" ) )
s |= UPDATE_RELEASE_STATUS_NEWER;
if( strstr( psz_arg, "equal" ) )
s |= UPDATE_RELEASE_STATUS_EQUAL;
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
{
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_Check( p_u );
msg_rc( "\nChecking for updates" );
if( update_CompareReleaseToCurrent( p_u ) == UpdateReleaseStatusNewer )
msg_rc( "\n+----[ VLC %i.%i.%i%s ] ", p_u->release.i_major,
p_u->release.i_minor,
p_u->release.i_revision,
p_u->release.psz_extra );
else
msg_rc( "\n+----Last version" );
update_Delete( p_u );
}
......@@ -35,15 +35,12 @@
#include <QFile>
#include <QLabel>
#include <QString>
#include <QCheckBox>
#include <QGroupBox>
#include <QDialogButtonBox>
#include <QFileDialog>
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" ) );
resize( 600, 560 );
......@@ -98,20 +95,20 @@ AboutDialog::AboutDialog( intf_thread_t *_p_intf) : QVLCFrame( _p_intf )
QLabel *infoLabel = new QLabel( "VLC media player " PACKAGE_VERSION "\n\n"
"(c) 1996-2007 - the VideoLAN Team\n\n" +
qtr( "VLC media player is a free media player, made by the "
"VideoLAN Team.\nIt is a standalone multimedia player, "
"encoder and streamer, that can read from many supports "
"(files, CDs, DVDs, networks, capture cards...) and that "
"works on many platforms.\n\n" )
"VideoLAN Team.\nIt is a standalone multimedia player, "
"encoder and streamer, that can read from many supports "
"(files, CDs, DVDs, networks, capture cards...) and that "
"works on many platforms.\n\n" )
+ qtr( "You are using the new Qt4 Interface.\n" )
+ qtr( "Compiled by " ) + qfu( VLC_CompileBy() )+ "@"
+ qfu( VLC_CompileDomain() ) + ".\n"
+ "Compiler: " + qfu( VLC_Compiler() ) +".\n"
+ "Compiler: " + qfu( VLC_Compiler() ) + ".\n"
+ qtr( "Based on SVN revision: " ) + qfu( VLC_Changeset() )
+ ".\n\n"
+ qtr( "This program comes with NO WARRANTY, to the extent "
"permitted by the law; read the distribution tab.\n\n" )
+ "The VideoLAN team <videolan@videolan.org> \n"
"http://www.videolan.org/\n") ;
"http://www.videolan.org/\n" );
infoLabel->setWordWrap( infoLabel );
QLabel *iconVLC2 = new QLabel;
......@@ -129,7 +126,7 @@ AboutDialog::AboutDialog( intf_thread_t *_p_intf) : QVLCFrame( _p_intf )
QWidget *thanksWidget = new QWidget( this );
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 "
"(and the missing ones...) for their collaboration to "
"provide the best software." ) );
......@@ -165,45 +162,32 @@ void AboutDialog::close()
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" ) );
resize( 230, 180 );
resize( 320, 120 );
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" ) );
updateButton = new QPushButton( qtr( "&Update List" ) );
QPushButton *updateButton = new QPushButton( qtr( "&Update List" ) );
updateButton->setDefault( true );
QDialogButtonBox *buttonBox = new QDialogButtonBox(Qt::Horizontal);
QDialogButtonBox *buttonBox = new QDialogButtonBox( Qt::Horizontal );
buttonBox->addButton( updateButton, QDialogButtonBox::ActionRole );
buttonBox->addButton( closeButton, QDialogButtonBox::AcceptRole );
QGroupBox *checkGroup = new QGroupBox( qtr( "Select Package" ) );
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( updateBrowser, 0, 0 );
layout->addWidget( buttonBox, 1, 0 );
BUTTONACT( updateButton, updateOrUpload() );
BUTTONACT( closeButton, close() );
p_update = update_New( _p_intf );
b_updated = false;
}
UpdateDialog::~UpdateDialog()
......@@ -218,101 +202,18 @@ void UpdateDialog::close()
void UpdateDialog::updateOrUpload()
{
if( !p_update ) return;
if( !b_updated )
update_Check( p_update );
if( update_CompareReleaseToCurrent( p_update ) == UpdateReleaseStatusNewer )
{
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 );
updateBrowser->setHtml( qtr( "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=\"utf-8\" /></head> \
<body><center><p>" ) + qtu( (QString)p_update->release.psz_desc ) +
qtr( "</p>You can download the latest version of VLC <a href=\"" ) +
qtu( (QString)p_update->release.psz_url ) + qtr( "\">here</a></center></body></html>" ) );
}
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 )
{
b_download = false;
switch( p_updateit->file.i_type )
{
case UPDATE_FILE_TYPE_INFO:
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 )
{
QString strFileName = p_updateit->file.psz_url;
strFileName.remove( 0, strFileName.lastIndexOf( "/" ) + 1 );
update_download( p_updateit, qtu( ( saveDir + strFileName ) ) );
}
}
}
updateBrowser->setHtml( "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=\"utf-8\" /></head> \
<body><center>You have the latest version of VLC.</center></body></html>" );
}
}
......@@ -29,7 +29,7 @@
#include "util/qvlcframe.hpp"
class QPushButton;
class QCheckBox;
class QTextBrowser;
class HelpDialog : public QVLCFrame
{
......@@ -44,7 +44,7 @@ public:
virtual ~HelpDialog();
private:
HelpDialog( intf_thread_t *);
HelpDialog( intf_thread_t * );
static HelpDialog *instance;
public slots:
void close();
......@@ -58,13 +58,13 @@ public:
static AboutDialog * getInstance( intf_thread_t *p_intf )
{
if( !instance)
instance = new AboutDialog( p_intf);
instance = new AboutDialog( p_intf );
return instance;
}
virtual ~AboutDialog();
private:
AboutDialog( intf_thread_t *);
AboutDialog( intf_thread_t * );
static AboutDialog *instance;
public slots:
void close();
......@@ -77,22 +77,17 @@ class UpdateDialog : public QVLCFrame
public:
static UpdateDialog * getInstance( intf_thread_t *p_intf )
{
if( !instance)
instance = new UpdateDialog( p_intf);
if( !instance )
instance = new UpdateDialog( p_intf );
return instance;
}
virtual ~UpdateDialog();
private:
UpdateDialog( intf_thread_t *);
UpdateDialog( intf_thread_t * );
static UpdateDialog *instance;
QPushButton *updateButton;
QCheckBox *checkInfo;
QCheckBox *checkSource;
QCheckBox *checkBinary;
QCheckBox *checkPlugin;
update_t *p_update;
bool b_updated;
QTextBrowser *updateBrowser;
private slots:
void close();
void updateOrUpload();
......
......@@ -21,11 +21,6 @@
* 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
* This file contains functions related to VLC and plugins update management
......@@ -45,65 +40,44 @@
#include <vlc_block.h>
#include <vlc_stream.h>
#include <vlc_xml.h>
#include <vlc_interface.h>
#include <vlc_charset.h>
#include <vlc_md5.h>
/*****************************************************************************
* Misc defines
*****************************************************************************/
/* All release notes and source packages should match on "*"
* Only binary installers are OS specific ( we only provide these
* for Win32, Mac OS X, WincCE, beos(?) ) */
//#define UPDATE_VLC_STATUS_URL "http://zen.via.ecp.fr/~ivoire/videolan/update"
#if defined( UNDER_CE )
# define UPDATE_VLC_OS "*"
# define UPDATE_VLC_ARCH "*"
# define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-ce"
#elif defined( WIN32 )
# define UPDATE_VLC_OS "windows"
# define UPDATE_VLC_ARCH "i386"
# define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-win-x86"
#elif defined( __APPLE__ )
# define UPDATE_VLC_OS "macosx"
# 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
# define UPDATE_VLC_ARCH "x86"
# define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-mac-x86"
# endif
#elif defined( SYS_BEOS )
# define UPDATE_VLC_OS "beos"
# define UPDATE_VLC_ARCH "i386"
# define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-beos-x86"
#else
# define UPDATE_VLC_OS "*"
# define UPDATE_VLC_ARCH "*"
# define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status"
#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 )
/*****************************************************************************
* 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
......@@ -128,22 +102,12 @@ update_t *__update_New( vlc_object_t *p_this )
p_update->p_libvlc = p_this->p_libvlc;
p_update->p_releases = NULL;
p_update->i_releases = 0;
p_update->b_releases = VLC_FALSE;
p_update->release.psz_svnrev = NULL;
p_update->release.psz_extra = NULL;
p_update->release.psz_url = NULL;
p_update->release.psz_desc = NULL;
p_update->p_mirrors = NULL;
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
return p_update;
}
/**
......@@ -157,284 +121,90 @@ void update_Delete( update_t *p_update )
assert( p_update );
vlc_mutex_destroy( &p_update->lock );
FreeMirrorsList( p_update );
FreeReleasesList( p_update );
free( p_update );
}
/**
* 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;
if( p_update->release.psz_svnrev )
{
free( p_update->release.psz_svnrev );
p_update->release.psz_svnrev = NULL;
}
for( i = 0; i < p_update->i_mirrors; i++ )
if( p_update->release.psz_extra )
{
free( p_update->p_mirrors[i].psz_name );
free( p_update->p_mirrors[i].psz_location );
free( p_update->p_mirrors[i].psz_type );
free( p_update->p_mirrors[i].psz_base_url );
free( p_update->release.psz_extra );
p_update->release.psz_extra = NULL;
}
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;
if( p_update->release.psz_url )
{
free( p_update->release.psz_url );
p_update->release.psz_url = NULL;
}
for( i = 0; i < p_update->i_releases; i++ )
if( p_update->release.psz_desc )
{
int j;
struct update_release_t *p_release = (p_update->p_releases + i);
for( j = 0; j < p_release->i_files; j++ )
{
free( p_release->p_files[j].psz_md5 );
free( p_release->p_files[j].psz_url );
free( p_release->p_files[j].psz_description );
}
free( p_release->psz_major );
free( p_release->psz_minor );
free( p_release->psz_revision );
free( p_release->psz_extra );
free( p_release->psz_svn_revision );
free( p_release->p_files );
free( p_update->release.psz_desc );
p_update->release.psz_desc = NULL;
}
FREENULL( p_update->p_releases );
p_update->i_releases = 0;
p_update->b_releases = VLC_FALSE;
free( p_update );
}
/**
* Get the mirrors list XML file and parse it
* *p_update has to be unlocked when calling this function
* Empty the release struct
*
* \param p_update pointer to the update struct
* \param b_force set to VLC_TRUE if you want to force the mirrors list update
* \param p_update update_t* pointer
* \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;
xml_t *p_xml = NULL;
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_update->release.i_major = 0;
p_update->release.i_minor = 0;
p_update->release.i_revision = 0;
p_stream = stream_UrlNew( p_update->p_libvlc, UPDATE_VLC_MIRRORS_URL );
if( !p_stream )
if( p_update->release.psz_svnrev )
{
msg_Err( p_update->p_libvlc, "Failed to open %s for reading",
UPDATE_VLC_MIRRORS_URL );
goto error;
free( p_update->release.psz_svnrev );
p_update->release.psz_svnrev = NULL;
}
p_xml_reader = xml_ReaderCreate( p_xml, p_stream );
if( !p_xml_reader )
if( p_update->release.psz_extra )
{
msg_Err( p_update->p_libvlc, "Failed to open %s for parsing",
UPDATE_VLC_MIRRORS_URL );
goto error;
free( p_update->release.psz_extra );
p_update->release.psz_extra = NULL;
}
if( p_update->p_mirrors )
if( p_update->release.psz_url )
{
FreeMirrorsList( p_update );
free( p_update->release.psz_url );
p_update->release.psz_url = NULL;
}
while( xml_ReaderRead( p_xml_reader ) == 1 )
if( p_update->release.psz_desc )
{
switch( xml_ReaderNodeType( p_xml_reader ) )
{
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 )
{
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",
UPDATE_VLC_MIRRORS_URL );
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" ) )
{
FREENULL( tmp_mirror.psz_name );
FREENULL( tmp_mirror.psz_location );
}
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 );
free( p_update->release.psz_desc );
p_update->release.psz_desc = NULL;
}
}
/**
* 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
*
* \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
*/
static void GetFilesList( update_t *p_update, vlc_bool_t b_force )
static void GetUpdateFile( update_t *p_update )
{
stream_t *p_stream = NULL;
xml_t *p_xml = NULL;
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_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;
int i_major = 0;
int i_minor = 0;
int i_revision = 0;
char *psz_extra = NULL;
char *psz_svnrev = NULL;
char *psz_line = NULL;
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 );
if( !p_stream )
{
......@@ -443,950 +213,171 @@ static void GetFilesList( update_t *p_update, vlc_bool_t b_force )
goto error;
}
p_xml_reader = xml_ReaderCreate( p_xml, p_stream );
if( !p_xml_reader )
/* Try to read three lines */
if( !( psz_line = stream_ReadLine( p_stream ) ) )
{
msg_Err( p_update->p_libvlc, "Failed to open %s for parsing",
msg_Err( p_update->p_libvlc, "Update file %s is corrupted : missing version",
UPDATE_VLC_STATUS_URL );
goto error;
}
if( p_update->p_releases )
/* first line : version number */
if( sscanf( psz_line, "%i.%i.%i%as %as", &i_major, &i_minor, &i_revision, &psz_extra, &psz_svnrev ) )
{
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",
UPDATE_VLC_STATUS_URL );
goto error;
}
while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
{
psz_name = xml_ReaderName( p_xml_reader );
psz_value = xml_ReaderValue( p_xml_reader );
p_update->release.i_major = i_major;
p_update->release.i_minor = i_minor;
p_update->release.i_revision = i_revision;
if( !psz_name || !psz_value )
{
msg_Err( p_update->p_libvlc, "Error while parsing %s",
UPDATE_VLC_STATUS_URL );
goto error;
}
if( psz_svnrev )
p_update->release.psz_svnrev = psz_svnrev;
else
p_update->release.psz_svnrev = STRDUP( "" );
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
tmp_release.i_type =
UPDATE_RELEASE_TYPE_STABLE;
}
}
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
tmp_file.i_type = UPDATE_FILE_TYPE_UNDEF;
}
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
{
FREENULL( tmp_release.psz_major );
FREENULL( tmp_release.psz_minor );
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;
}
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;
if( psz_extra )
p_update->release.psz_extra = psz_extra;
else
p_update->release.psz_extra = STRDUP( "" );
}
else
{
msg_Err( p_update->p_libvlc, "Update version false formated" );
free( psz_line );
goto error;
}
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_STATUS_URL );
goto error;
}
/* Second line : URL */
if( !( psz_line = stream_ReadLine( p_stream ) ) )
{
msg_Err( p_update->p_libvlc, "Update file %s is corrupted : URL missing",
UPDATE_VLC_STATUS_URL );
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:
psz_eltvalue = xml_ReaderValue( p_xml_reader );
if( p_release && p_release->i_files )
p_release->p_files[ p_release->i_files - 1 ]
.psz_description = STRDUP( psz_eltvalue );
FREENULL( psz_eltvalue );
break;
}
/* Third line : description */
if( !( psz_line = stream_ReadLine( p_stream ) ) )
{
msg_Err( p_update->p_libvlc, "Update file %s is corrupted : description missing",
UPDATE_VLC_STATUS_URL );
goto error;
}
p_update->b_releases = VLC_TRUE;
p_update->release.psz_desc = psz_line;
error:
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 )
stream_Delete( p_stream );
if( p_xml )
xml_Delete( p_xml );
}
/**
* Check for updates
*
* \param p_update pointer to update struct
* \param b_force set to VLC_TRUE if you want to force the update
* \returns nothing
*/
void update_Check( update_t *p_update, vlc_bool_t b_force )
void update_Check( update_t *p_update )
{
assert( p_update );
GetMirrorsList( p_update, b_force );
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;
}
/**
* Delete an update iterator structure (duh!)
*
* \param p_uit pointer to an update iterator
* \return nothing
*/
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;
EmptyRelease( p_update );
update_iterator_ClearData( p_uit );
return UPDATE_SUCCESS;
GetUpdateFile( p_update );
}
/**
* Finds the next file in the update tree that matches status and type
* requirements set in the update_iterator
* Compare two integers
*
* \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
* \param p1 first integer
* \param p2 second integer
* \return like strcmp
*/
//TODO: test
static unsigned int update_iterator_PrevFile( update_iterator_t *p_uit )
static int cmp( int i1, int i2 )
{
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;
}
if( i1 < i2 )
return -1;
else if(i1 == i2)
return 0;
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;
return 1;
}
/**
* Change the update iterator's position in the file and mirrors tree
* If position is negative, don't change it
* Compare two release numbers
*
* \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
* \param p1 first release
* \param p2 second release
* \return UpdateReleaseStatus(Older|Equal|Newer)
*/
unsigned int update_iterator_ChooseMirrorAndFile( update_iterator_t *p_uit,
int i_m, int i_r, int i_f )
static int CompareReleases( const struct update_release_t *p1,
const struct update_release_t *p2 )
{
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;
}
int d;
if( ( d = cmp( p1->i_major, p2->i_major ) ) ) ;
else if( ( d = cmp( p1->i_minor, p2->i_minor ) ) ) ;
else if( ( d = cmp( p1->i_revision, p2->i_revision ) ) ) ;
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 )
{
struct update_release_t *p_r = NULL;
struct update_file_t *p_f = NULL;
struct update_mirror_t *p_m = NULL;
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 )
if( p1->psz_extra[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 );
}
}
if( p2->psz_extra[0] == '-' )
d = strcmp( p1->psz_extra, p2->psz_extra );
else
{
p_uit->file.psz_url = STRDUP( p_f->psz_url );
}
}
}
}
/**
* Clears the iterator data (file, release and mirror structs)
*
* \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 i_action update action bitmask. can be a combination of UPDATE_NEXT, UPDATE_PREV, UPDATE_MIRROR, UPDATE_RELEASE, UPDATE_FILE, UPDATE_RESET
* \return UPDATE_FAIL if action fails, UPDATE_SUCCESS|(combination of UPDATE_MIRROR, UPDATE_RELEASE and UPDATE_FILE if these changed) otherwise
*/
unsigned int update_iterator_Action( update_iterator_t *p_uit, int i_action )
{
if( i_action & UPDATE_RESET )
{
return update_iterator_Reset( p_uit );
}
else
if( i_action & UPDATE_MIRROR )
{
if( i_action & UPDATE_PREV )
{
return update_iterator_PrevMirror( p_uit );
}
else
{
return update_iterator_NextMirror( p_uit );
}
}
/*else if( i_action & UPDATE_RELEASE )
{
if( i_action & UPDATE_PREV )
{
return update_iterator_PrevRelease( p_uit );
}
else
{
return update_iterator_NextRelease( p_uit );
}
}*/
else if( i_action & UPDATE_FILE )
{
if( i_action & UPDATE_PREV )
{
return update_iterator_PrevFile( p_uit );
d = 1;
}
else
{
return update_iterator_NextFile( p_uit );
if( p2->psz_extra[0] == '-' )
d = -1;
else
d = strcmp(p1->psz_extra, p2->psz_extra );
}
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 );
/**
* Download the file selected by the update iterator. This function will
* launch the download in a new thread (downloads can be long)
*
* \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) );
if( d < 0 )
return UpdateReleaseStatusOlder;
else if( d == 0 )
return UpdateReleaseStatusEqual;
else
asprintf( &psz_tmp, "%ld B", l_size );
return psz_tmp;
return UpdateReleaseStatusNewer;
}
/**
* 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
* \return nothing
* \param p a release
* \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;
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 );
assert( p_update );
p_stream = stream_UrlNew( p_libvlc, psz_src );
if( !p_stream )
{
msg_Err( p_libvlc, "Failed to open %s for reading", psz_src );
intf_UserFatal( p_libvlc, VLC_TRUE, "Download Error",
"VLC failed to open %s for reading.", psz_src );
intf_UserHide( p_libvlc, i_progress );
}
else
{
l_size = stream_Size(p_stream);
if( l_size != p_this->src.l_size )
{
stream_Delete( p_stream );
free( psz_status );
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 );
}
struct update_release_t c;
int i_major = 0;
int i_minor = 0;
int i_revision = 0;
char *psz_extra;
int i_result = UpdateReleaseStatusOlder;
/* get the current version number */
if( sscanf( PACKAGE_VERSION, "%i.%i.%i%as", &i_major, &i_minor, &i_revision, &psz_extra ) )
{
c.i_major = i_major;
c.i_minor = i_minor;
c.i_revision = i_revision;
if( psz_extra )
c.psz_extra = psz_extra;
else
{
int i_read;
char *psz_s1; char *psz_s2;
struct md5_s md5_s;
c.psz_extra = STRDUP( "" );
c.psz_svnrev = STRDUP( VLC_Changeset() );
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;
i_result = CompareReleases( &p_update->release, &c );
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;
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,
psz_status, f_progress, 0 );
}
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 );
}
free( c.psz_extra );
free( c.psz_svnrev );
}
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 );
return i_result;
}
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