2014-11-21 17:11:57 +01:00
///////////////////////////////////////////////////////////////////////////////
// MuldeR's Utilities for Qt
2017-01-06 23:17:56 +01:00
// Copyright (C) 2004-2017 LoRd_MuldeR <MuldeR2@GMX.de>
2014-11-21 17:11:57 +01:00
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
// http://www.gnu.org/licenses/lgpl-2.1.txt
//////////////////////////////////////////////////////////////////////////////////
2014-11-21 17:54:46 +01:00
# include <MUtils/Global.h>
2014-11-21 19:42:39 +01:00
# include <MUtils/UpdateChecker.h>
# include <MUtils/OSSupport.h>
# include <MUtils/Exception.h>
2014-11-21 17:11:57 +01:00
# include <QStringList>
# include <QFile>
# include <QFileInfo>
# include <QProcess>
# include <QUrl>
# include <QEventLoop>
# include <QTimer>
2017-03-27 23:38:43 +02:00
# include <QElapsedTimer>
2014-11-21 17:11:57 +01:00
using namespace MUtils ;
///////////////////////////////////////////////////////////////////////////////
// CONSTANTS
///////////////////////////////////////////////////////////////////////////////
static const char * header_id = " !Update " ;
static const char * mirror_url_postfix [ ] =
{
" update.ver " ,
" update_beta.ver " ,
NULL
} ;
2016-04-23 13:25:01 +02:00
static const char * update_mirrors [ ] =
2014-11-21 17:11:57 +01:00
{
" http://muldersoft.com/ " ,
2016-10-22 15:10:58 +02:00
" http://mulder.bplaced.net/ " ,
2014-11-21 17:11:57 +01:00
" http://mulder.6te.net/ " ,
2016-10-22 15:10:58 +02:00
" http://mulder.webuda.com/ " ,
" http://mulder.pe.hu/ " ,
" http://muldersoft.square7.ch/ " ,
2015-02-22 20:26:13 +01:00
" http://muldersoft.co.nf/ " ,
2015-02-26 21:42:39 +01:00
" http://muldersoft.eu.pn/ " ,
2015-10-18 18:07:04 +02:00
" http://muldersoft.lima-city.de/ " ,
2015-10-20 20:53:35 +02:00
" http://www.muldersoft.keepfree.de/ " ,
2014-11-21 17:11:57 +01:00
" http://lamexp.sourceforge.net/ " ,
" http://lordmulder.github.io/LameXP/ " ,
2017-01-14 22:20:10 +01:00
" http://muldersoft.bitbucket.io/ " , //http://lord_mulder.bitbucket.org/
2014-11-21 17:11:57 +01:00
" http://www.tricksoft.de/ " ,
2016-10-22 15:10:58 +02:00
" http://repo.or.cz/LameXP.git/blob_plain/gh-pages:/ " ,
" http://gitlab.com/lamexp/lamexp/raw/gh-pages/ " ,
2014-11-21 17:11:57 +01:00
NULL
} ;
static const char * known_hosts [ ] = //Taken form: http://www.alexa.com/topsites !!!
{
2016-04-23 13:25:01 +02:00
" www.163.com " ,
" www.7-zip.org " ,
" www.ac3filter.net " ,
" clbianco.altervista.org " ,
" status.aws.amazon.com " ,
" build.antergos.com " ,
" www.aol.com " ,
" www.apache.org " ,
" www.apple.com " ,
" www.adobe.com " ,
" archive.org " ,
" www.artlebedev.ru " ,
" web.audacityteam.org " ,
" status.automattic.com " ,
" www.avidemux.org " ,
" www.babylon.com " ,
" www.baidu.com " ,
" bandcamp.com " ,
" www.bbc.co.uk " ,
" www.berlios.de " ,
" www.bing.com " ,
" www.bingeandgrab.com " ,
" www.bucketheadpikes.com " ,
" www.buckethead-coop.com " ,
" www.buzzfeed.com " ,
2017-03-27 23:38:43 +02:00
" www.cam.ac.uk " ,
2016-04-23 13:25:01 +02:00
" www.ccc.de " ,
2017-03-27 23:38:43 +02:00
" home.cern " ,
2016-04-23 13:25:01 +02:00
" www.citizeninsomniac.com " ,
" www.cnet.com " ,
" cnzz.com " ,
" www.codeplex.com " ,
" www.codeproject.com " ,
" www.der-postillon.com " ,
" www.ebay.com " ,
" www.equation.com " ,
" www.farbrausch.de " ,
" fc2.com " ,
" fedoraproject.org " ,
" blog.fefe.de " ,
" www.ffmpeg.org " ,
" blog.flickr.net " ,
2017-03-27 23:38:43 +02:00
" www.fraunhofer.de " ,
2016-04-23 13:25:01 +02:00
" free-codecs.com " ,
" git-scm.com " ,
" doc.gitlab.com " ,
" www.gmx.net " ,
" news.gnome.org " ,
" www.gnu.org " ,
" go.com " ,
" code.google.com " ,
" haali.su " ,
2017-03-27 23:38:43 +02:00
" www.harvard.edu " ,
2016-04-23 13:25:01 +02:00
" www.heise.de " ,
" www.huffingtonpost.co.uk " ,
2017-03-27 23:38:43 +02:00
" www.hu-berlin.de " ,
2016-04-23 13:25:01 +02:00
" www.iana.org " ,
" www.imdb.com " ,
" www.imgburn.com " ,
" imgur.com " ,
" www.jd.com " ,
" www.jiscdigitalmedia.ac.uk " ,
" kannmanumdieuhrzeitschonnbierchentrinken.de " ,
" mirrors.kernel.org " ,
" komisar.gin.by " ,
" lame.sourceforge.net " ,
" www.libav.org " ,
" blog.linkedin.com " ,
" www.linuxmint.com " ,
" www.livedoor.com " ,
" www.livejournal.com " ,
" longplayer.org " ,
" go.mail.ru " ,
" marknelson.us " ,
" www.mediafire.com " ,
2017-03-27 23:38:43 +02:00
" web.mit.edu " ,
2016-04-23 13:25:01 +02:00
" www.mod-technologies.com " ,
" ftp.mozilla.org " ,
2017-03-27 23:38:43 +02:00
" www.mpg.de " ,
2016-04-23 13:25:01 +02:00
" mplayerhq.hu " ,
" www.msn.com " ,
" wiki.multimedia.cx " ,
" www.nch.com.au " ,
" mirror.netcologne.de " ,
" oss.netfarm.it " ,
" blog.netflix.com " ,
" netrenderer.de " ,
" www.nytimes.com " ,
" www.opera.com " ,
2017-03-27 23:38:43 +02:00
" www.oxford.gov.uk " ,
2016-04-23 13:25:01 +02:00
" www.partha.com " ,
" pastebin.com " ,
" pastie.org " ,
" portableapps.com " ,
" www.portablefreeware.com " ,
" support.proboards.com " ,
" www.qq.com " ,
" www.qt.io " ,
" www.quakelive.com " ,
" rationalqm.us " ,
2017-03-27 23:38:43 +02:00
" www.rwth-aachen.de " ,
2016-04-23 13:25:01 +02:00
" www.seamonkey-project.org " ,
" selfhtml.org " ,
" www.sina.com.cn " ,
" www.sohu.com " ,
" help.sogou.com " ,
" sourceforge.net " ,
" www.spiegel.de " ,
" www.sputnikmusic.com " ,
" stackoverflow.com " ,
2017-03-27 23:38:43 +02:00
" www.stanford.edu " ,
2016-04-23 13:25:01 +02:00
" www.t-online.de " ,
" www.tagesschau.de " ,
" tdm-gcc.tdragon.net " ,
" www.tdrsmusic.com " ,
2017-03-27 23:38:43 +02:00
" tu-dresden.de " ,
2016-04-23 13:25:01 +02:00
" www.ubuntu.com " ,
" www.uol.com.br " ,
" www.videohelp.com " ,
" www.videolan.org " ,
" virtualdub.org " ,
" blog.virustotal.com " ,
" www.vkgoeswild.com " ,
" www.warr.org " ,
" www.weibo.com " ,
" status.wikimedia.org " ,
" www.winamp.com " ,
" www.winhoros.de " ,
" wpde.org " ,
" x265.org " ,
" xhmikosr.1f0.de " ,
" xiph.org " ,
" us.mail.yahoo.com " ,
" www.youtube.com " ,
" www.zedo.com " ,
" ffmpeg.zeranoe.com " ,
2014-11-21 17:11:57 +01:00
NULL
} ;
2016-04-23 18:36:19 +02:00
static const int MIN_CONNSCORE = 5 ;
2017-03-27 23:38:43 +02:00
static const int MAX_CONN_TIMEOUT = 8000 ;
static const int DOWNLOAD_TIMEOUT = 30000 ;
2014-11-21 17:11:57 +01:00
static const int VERSION_INFO_EXPIRES_MONTHS = 6 ;
2016-10-22 15:10:58 +02:00
static char * USER_AGENT_STR = " Mozilla/5.0 (X11; Linux i686; rv:10.0) Gecko/20100101 Firefox/10.0 " ; /*use something innocuous*/
2014-11-21 17:11:57 +01:00
2016-04-23 18:36:19 +02:00
////////////////////////////////////////////////////////////
// Helper Functions
////////////////////////////////////////////////////////////
2014-11-21 17:11:57 +01:00
static int getMaxProgress ( void )
{
int counter = MIN_CONNSCORE + 2 ;
2016-04-23 13:25:01 +02:00
for ( int i = 0 ; update_mirrors [ i ] ; i + + ) counter + + ;
2014-11-21 17:11:57 +01:00
return counter ;
}
2016-04-23 13:25:01 +02:00
static QStringList buildRandomList ( const char * const values [ ] )
{
QStringList list ;
for ( int index = 0 ; values [ index ] ; index + + )
{
2016-12-16 19:23:35 +01:00
const int pos = next_rand_u32 ( ) % ( index + 1 ) ;
2016-04-23 13:25:01 +02:00
list . insert ( pos , QString : : fromLatin1 ( values [ index ] ) ) ;
}
return list ;
}
2014-11-21 17:11:57 +01:00
////////////////////////////////////////////////////////////
// Update Info Class
////////////////////////////////////////////////////////////
UpdateCheckerInfo : : UpdateCheckerInfo ( void )
{
resetInfo ( ) ;
}
void UpdateCheckerInfo : : resetInfo ( void )
{
m_buildNo = 0 ;
m_buildDate . setDate ( 1900 , 1 , 1 ) ;
m_downloadSite . clear ( ) ;
m_downloadAddress . clear ( ) ;
m_downloadFilename . clear ( ) ;
m_downloadFilecode . clear ( ) ;
2015-08-16 16:27:43 +02:00
m_downloadChecksum . clear ( ) ;
}
bool UpdateCheckerInfo : : isComplete ( void )
{
if ( this - > m_buildNo < 1 ) return false ;
if ( this - > m_buildDate . year ( ) < 2010 ) return false ;
if ( this - > m_downloadSite . isEmpty ( ) ) return false ;
if ( this - > m_downloadAddress . isEmpty ( ) ) return false ;
if ( this - > m_downloadFilename . isEmpty ( ) ) return false ;
if ( this - > m_downloadFilecode . isEmpty ( ) ) return false ;
if ( this - > m_downloadChecksum . isEmpty ( ) ) return false ;
return true ;
2014-11-21 17:11:57 +01:00
}
////////////////////////////////////////////////////////////
// Constructor & Destructor
////////////////////////////////////////////////////////////
2016-04-23 13:25:01 +02:00
UpdateChecker : : UpdateChecker ( const QString & binWGet , const QString & binNC , const QString & binGnuPG , const QString & binKeys , const QString & applicationId , const quint32 & installedBuildNo , const bool betaUpdates , const bool testMode )
2014-11-21 17:11:57 +01:00
:
m_updateInfo ( new UpdateCheckerInfo ( ) ) ,
m_binaryWGet ( binWGet ) ,
2016-04-23 13:25:01 +02:00
m_binaryNC ( binNC ) ,
2014-11-21 17:11:57 +01:00
m_binaryGnuPG ( binGnuPG ) ,
m_binaryKeys ( binKeys ) ,
2014-11-21 20:56:36 +01:00
m_applicationId ( applicationId ) ,
2014-11-21 19:51:21 +01:00
m_installedBuildNo ( installedBuildNo ) ,
2014-11-21 17:11:57 +01:00
m_betaUpdates ( betaUpdates ) ,
m_testMode ( testMode ) ,
m_maxProgress ( getMaxProgress ( ) )
{
m_success = false ;
m_status = UpdateStatus_NotStartedYet ;
m_progress = 0 ;
if ( m_binaryWGet . isEmpty ( ) | | m_binaryGnuPG . isEmpty ( ) | | m_binaryKeys . isEmpty ( ) )
{
2014-11-21 19:42:39 +01:00
MUTILS_THROW ( " Tools not initialized correctly! " ) ;
2014-11-21 17:11:57 +01:00
}
}
UpdateChecker : : ~ UpdateChecker ( void )
{
}
////////////////////////////////////////////////////////////
// Protected functions
////////////////////////////////////////////////////////////
void UpdateChecker : : run ( void )
{
qDebug ( " Update checker thread started! " ) ;
2014-11-21 19:42:39 +01:00
MUTILS_EXCEPTION_HANDLER ( m_testMode ? testKnownHosts ( ) : checkForUpdates ( ) ) ;
2014-11-21 17:11:57 +01:00
qDebug ( " Update checker thread completed. " ) ;
}
void UpdateChecker : : checkForUpdates ( void )
{
// ----- Initialization ----- //
m_success = false ;
m_updateInfo - > resetInfo ( ) ;
setProgress ( 0 ) ;
// ----- Test Internet Connection ----- //
2016-04-23 13:25:01 +02:00
log ( " Checking internet connection... " , " " ) ;
2014-11-21 17:11:57 +01:00
setStatus ( UpdateStatus_CheckingConnection ) ;
2014-11-21 20:11:39 +01:00
const int networkStatus = OS : : network_status ( ) ;
if ( networkStatus = = OS : : NETWORK_TYPE_NON )
2014-11-21 17:11:57 +01:00
{
2016-04-23 13:25:01 +02:00
log ( " Operating system reports that the computer is currently offline !!! " ) ;
2014-11-21 17:11:57 +01:00
setProgress ( m_maxProgress ) ;
setStatus ( UpdateStatus_ErrorNoConnection ) ;
return ;
}
setProgress ( 1 ) ;
// ----- Test Known Hosts Connectivity ----- //
2017-03-27 23:38:43 +02:00
int connectionScore = 0 , connectionTimout = 125 ;
2016-04-23 13:25:01 +02:00
QStringList hostList = buildRandomList ( known_hosts ) ;
2017-03-27 23:38:43 +02:00
while ( connectionScore < MIN_CONNSCORE )
2014-11-21 17:11:57 +01:00
{
2017-03-27 23:38:43 +02:00
connectionTimout * = 2 ;
if ( connectionTimout > MAX_CONN_TIMEOUT )
{
break ;
}
QElapsedTimer elapsedTimer ;
const int globalTimout = 250 + ( 13 * connectionTimout ) ;
elapsedTimer . start ( ) ;
while ( ! elapsedTimer . hasExpired ( globalTimout ) )
2014-11-21 17:11:57 +01:00
{
2017-03-27 23:38:43 +02:00
const QString hostName = hostList . takeFirst ( ) ;
if ( tryContactHost ( hostName , connectionTimout ) )
{
connectionScore + = 1 ;
setProgress ( qBound ( 1 , connectionScore + 1 , MIN_CONNSCORE + 1 ) ) ;
elapsedTimer . restart ( ) ;
if ( connectionScore > = MIN_CONNSCORE )
{
break ; /*success*/
}
}
else
{
hostList . append ( hostName ) ; /*re-schedule*/
}
msleep ( 1 ) ;
2014-11-21 17:11:57 +01:00
}
}
if ( connectionScore < MIN_CONNSCORE )
{
log ( " " , " Connectivity test has failed: Internet connection appears to be broken! " ) ;
setProgress ( m_maxProgress ) ;
setStatus ( UpdateStatus_ErrorConnectionTestFailed ) ;
return ;
}
2016-04-23 13:25:01 +02:00
// ----- Fetch Update Info From Server ----- //
2014-11-21 17:11:57 +01:00
2016-04-23 13:25:01 +02:00
log ( " ---- " , " " , " Checking for updates online... " ) ;
2014-11-21 17:11:57 +01:00
setStatus ( UpdateStatus_FetchingUpdates ) ;
2016-04-23 13:25:01 +02:00
QStringList mirrorList = buildRandomList ( update_mirrors ) ;
2014-11-21 17:11:57 +01:00
while ( ! mirrorList . isEmpty ( ) )
{
QString currentMirror = mirrorList . takeFirst ( ) ;
setProgress ( m_progress + 1 ) ;
if ( ! m_success )
{
2015-08-16 16:27:43 +02:00
if ( tryUpdateMirror ( m_updateInfo . data ( ) , currentMirror ) )
2014-11-21 17:11:57 +01:00
{
m_success = true ;
}
}
else
{
2016-04-23 13:25:01 +02:00
msleep ( 25 ) ;
2014-11-21 17:11:57 +01:00
}
}
setProgress ( m_maxProgress ) ;
if ( m_success )
{
2014-11-21 19:51:21 +01:00
if ( m_updateInfo - > m_buildNo > m_installedBuildNo )
2014-11-21 17:11:57 +01:00
{
setStatus ( UpdateStatus_CompletedUpdateAvailable ) ;
}
2014-11-21 19:51:21 +01:00
else if ( m_updateInfo - > m_buildNo = = m_installedBuildNo )
2014-11-21 17:11:57 +01:00
{
setStatus ( UpdateStatus_CompletedNoUpdates ) ;
}
else
{
setStatus ( UpdateStatus_CompletedNewVersionOlder ) ;
}
}
else
{
setStatus ( UpdateStatus_ErrorFetchUpdateInfo ) ;
}
}
void UpdateChecker : : testKnownHosts ( void )
{
QStringList hostList ;
for ( int i = 0 ; known_hosts [ i ] ; i + + )
{
hostList < < QString : : fromLatin1 ( known_hosts [ i ] ) ;
}
qDebug ( " \n [Known Hosts] " ) ;
log ( " Testing all known hosts... " , " " , " --- " ) ;
int hostCount = hostList . count ( ) ;
while ( ! hostList . isEmpty ( ) )
{
QString currentHost = hostList . takeFirst ( ) ;
qDebug ( " Testing: %s " , currentHost . toLatin1 ( ) . constData ( ) ) ;
log ( " " , " Testing: " , currentHost , " " ) ;
2017-03-27 23:38:43 +02:00
if ( ! tryContactHost ( currentHost , DOWNLOAD_TIMEOUT ) )
2014-11-21 17:11:57 +01:00
{
2016-04-23 13:25:01 +02:00
qWarning ( " \n Connectivity test FAILED on the following host: \n %s \n " , currentHost . toLatin1 ( ) . constData ( ) ) ;
2014-11-21 17:11:57 +01:00
}
log ( " " , " --- " ) ;
}
}
////////////////////////////////////////////////////////////
// PRIVATE FUNCTIONS
////////////////////////////////////////////////////////////
void UpdateChecker : : setStatus ( const int status )
{
if ( m_status ! = status )
{
m_status = status ;
emit statusChanged ( status ) ;
}
}
void UpdateChecker : : setProgress ( const int progress )
{
if ( m_progress ! = progress )
{
m_progress = progress ;
emit progressChanged ( progress ) ;
}
}
void UpdateChecker : : log ( const QString & str1 , const QString & str2 , const QString & str3 , const QString & str4 )
{
if ( ! str1 . isNull ( ) ) emit messageLogged ( str1 ) ;
if ( ! str2 . isNull ( ) ) emit messageLogged ( str2 ) ;
if ( ! str3 . isNull ( ) ) emit messageLogged ( str3 ) ;
if ( ! str4 . isNull ( ) ) emit messageLogged ( str4 ) ;
}
bool UpdateChecker : : tryUpdateMirror ( UpdateCheckerInfo * updateInfo , const QString & url )
{
bool success = false ;
2017-03-27 23:38:43 +02:00
log ( " " , " Trying mirror: " , url , " " ) ;
if ( ! tryContactHost ( QUrl ( url ) . host ( ) , MAX_CONN_TIMEOUT ) )
{
log ( " " , " Mirror is unreachable! " ) ;
return false ;
}
2014-11-21 17:11:57 +01:00
2016-12-16 19:23:35 +01:00
const QString randPart = next_rand_str ( ) ;
2014-11-21 17:54:46 +01:00
const QString outFileVers = QString ( " %1/%2.ver " ) . arg ( temp_folder ( ) , randPart ) ;
const QString outFileSign = QString ( " %1/%2.sig " ) . arg ( temp_folder ( ) , randPart ) ;
2014-11-21 17:11:57 +01:00
2017-03-27 23:38:43 +02:00
if ( getUpdateInfo ( url , outFileVers , outFileSign ) )
2014-11-21 17:11:57 +01:00
{
log ( " " , " Download okay, checking signature: " ) ;
2017-03-27 23:38:43 +02:00
if ( checkSignature ( outFileVers , outFileSign ) )
2014-11-21 17:11:57 +01:00
{
log ( " " , " Signature okay, parsing info: " ) ;
success = parseVersionInfo ( outFileVers , updateInfo ) ;
}
else
{
log ( " " , " Bad signature, take care! " ) ;
}
}
else
{
log ( " " , " Download has failed! " ) ;
}
QFile : : remove ( outFileVers ) ;
QFile : : remove ( outFileSign ) ;
return success ;
}
bool UpdateChecker : : getUpdateInfo ( const QString & url , const QString & outFileVers , const QString & outFileSign )
{
2017-03-27 23:38:43 +02:00
log ( " Downloading update info: " ) ;
2015-08-24 22:49:45 +02:00
if ( ! getFile ( QString ( " %1%2 " ) . arg ( url , mirror_url_postfix [ m_betaUpdates ? 1 : 0 ] ) , outFileVers ) )
2014-11-21 17:11:57 +01:00
{
return false ;
}
log ( " " , " Downloading signature: " ) ;
2015-08-24 22:49:45 +02:00
if ( ! getFile ( QString ( " %1%2.sig2 " ) . arg ( url , mirror_url_postfix [ m_betaUpdates ? 1 : 0 ] ) , outFileSign ) )
2014-11-21 17:11:57 +01:00
{
return false ;
}
return true ;
}
2016-04-23 13:25:01 +02:00
bool UpdateChecker : : parseVersionInfo ( const QString & file , UpdateCheckerInfo * updateInfo )
{
QRegExp value ( " ^( \\ w+) = ( . + ) $ " ) ;
QRegExp section ( " ^ \\ [(.+) \ \ ] $ " ) ;
QDate updateInfoDate ;
updateInfo - > resetInfo ( ) ;
QFile data ( file ) ;
if ( ! data . open ( QIODevice : : ReadOnly ) )
{
qWarning ( " Cannot open update info file for reading! " ) ;
return false ;
}
bool inHdr = false ;
bool inSec = false ;
while ( ! data . atEnd ( ) )
{
QString line = QString : : fromLatin1 ( data . readLine ( ) ) . trimmed ( ) ;
if ( section . indexIn ( line ) > = 0 )
{
log ( QString ( " Sec: [%1] " ) . arg ( section . cap ( 1 ) ) ) ;
inSec = ( section . cap ( 1 ) . compare ( m_applicationId , Qt : : CaseInsensitive ) = = 0 ) ;
inHdr = ( section . cap ( 1 ) . compare ( QString : : fromLatin1 ( header_id ) , Qt : : CaseInsensitive ) = = 0 ) ;
continue ;
}
if ( inSec & & ( value . indexIn ( line ) > = 0 ) )
{
log ( QString ( " Val: '%1' ==> '%2 " ) . arg ( value . cap ( 1 ) , value . cap ( 2 ) ) ) ;
if ( value . cap ( 1 ) . compare ( " BuildNo " , Qt : : CaseInsensitive ) = = 0 )
{
bool ok = false ;
const unsigned int temp = value . cap ( 2 ) . toUInt ( & ok ) ;
if ( ok ) updateInfo - > m_buildNo = temp ;
}
else if ( value . cap ( 1 ) . compare ( " BuildDate " , Qt : : CaseInsensitive ) = = 0 )
{
const QDate temp = QDate : : fromString ( value . cap ( 2 ) . trimmed ( ) , Qt : : ISODate ) ;
if ( temp . isValid ( ) ) updateInfo - > m_buildDate = temp ;
}
else if ( value . cap ( 1 ) . compare ( " DownloadSite " , Qt : : CaseInsensitive ) = = 0 )
{
updateInfo - > m_downloadSite = value . cap ( 2 ) . trimmed ( ) ;
}
else if ( value . cap ( 1 ) . compare ( " DownloadAddress " , Qt : : CaseInsensitive ) = = 0 )
{
updateInfo - > m_downloadAddress = value . cap ( 2 ) . trimmed ( ) ;
}
else if ( value . cap ( 1 ) . compare ( " DownloadFilename " , Qt : : CaseInsensitive ) = = 0 )
{
updateInfo - > m_downloadFilename = value . cap ( 2 ) . trimmed ( ) ;
}
else if ( value . cap ( 1 ) . compare ( " DownloadFilecode " , Qt : : CaseInsensitive ) = = 0 )
{
updateInfo - > m_downloadFilecode = value . cap ( 2 ) . trimmed ( ) ;
}
else if ( value . cap ( 1 ) . compare ( " DownloadChecksum " , Qt : : CaseInsensitive ) = = 0 )
{
updateInfo - > m_downloadChecksum = value . cap ( 2 ) . trimmed ( ) ;
}
}
if ( inHdr & & ( value . indexIn ( line ) > = 0 ) )
{
log ( QString ( " Val: '%1' ==> '%2 " ) . arg ( value . cap ( 1 ) , value . cap ( 2 ) ) ) ;
if ( value . cap ( 1 ) . compare ( " TimestampCreated " , Qt : : CaseInsensitive ) = = 0 )
{
QDate temp = QDate : : fromString ( value . cap ( 2 ) . trimmed ( ) , Qt : : ISODate ) ;
if ( temp . isValid ( ) ) updateInfoDate = temp ;
}
}
}
if ( ! updateInfoDate . isValid ( ) )
{
updateInfo - > resetInfo ( ) ;
log ( " WARNING: Version info timestamp is missing! " ) ;
return false ;
}
const QDate currentDate = OS : : current_date ( ) ;
if ( updateInfoDate . addMonths ( VERSION_INFO_EXPIRES_MONTHS ) < currentDate )
{
updateInfo - > resetInfo ( ) ;
log ( QString : : fromLatin1 ( " WARNING: This version info has expired at %1! " ) . arg ( updateInfoDate . addMonths ( VERSION_INFO_EXPIRES_MONTHS ) . toString ( Qt : : ISODate ) ) ) ;
return false ;
}
else if ( currentDate < updateInfoDate )
{
log ( " Version info is from the future, take care! " ) ;
qWarning ( " Version info is from the future, take care! " ) ;
}
if ( ! updateInfo - > isComplete ( ) )
{
log ( " WARNING: Version info is incomplete! " ) ;
return false ;
}
return true ;
}
//----------------------------------------------------------
// EXTERNAL TOOLS
//----------------------------------------------------------
2017-03-27 23:38:43 +02:00
bool UpdateChecker : : getFile ( const QString & url , const QString & outFile , const unsigned int maxRedir )
2015-08-24 21:49:15 +02:00
{
2016-04-23 13:25:01 +02:00
for ( int i = 0 ; i < 2 ; i + + )
2015-08-24 21:49:15 +02:00
{
2017-03-27 23:38:43 +02:00
if ( getFile ( url , ( i > 0 ) , outFile , maxRedir ) )
2015-08-24 21:49:15 +02:00
{
return true ;
}
}
return false ;
}
2017-03-27 23:38:43 +02:00
bool UpdateChecker : : getFile ( const QString & url , const bool forceIp4 , const QString & outFile , const unsigned int maxRedir )
2014-11-21 17:11:57 +01:00
{
QFileInfo output ( outFile ) ;
output . setCaching ( false ) ;
2016-04-23 13:25:01 +02:00
if ( output . exists ( ) )
2014-11-21 17:11:57 +01:00
{
QFile : : remove ( output . canonicalFilePath ( ) ) ;
2016-04-23 13:25:01 +02:00
if ( output . exists ( ) )
2014-11-21 17:11:57 +01:00
{
return false ;
}
}
QProcess process ;
2014-11-21 17:54:46 +01:00
init_process ( process , output . absolutePath ( ) ) ;
2014-11-21 17:11:57 +01:00
QStringList args ;
2016-04-23 13:25:01 +02:00
if ( forceIp4 )
2015-08-24 21:49:15 +02:00
{
args < < " -4 " ;
}
2016-10-22 15:10:58 +02:00
args < < " --no-config " < < " --no-cache " < < " --no-dns-cache " < < " --no-check-certificate " < < " --no-hsts " ;
2017-03-27 23:38:43 +02:00
args < < QString ( ) . sprintf ( " --max-redirect=%u " , maxRedir ) < < QString ( ) . sprintf ( " --timeout=%u " , DOWNLOAD_TIMEOUT / 1000 ) ;
2014-11-21 17:11:57 +01:00
args < < QString ( " --referer=%1://%2/ " ) . arg ( QUrl ( url ) . scheme ( ) , QUrl ( url ) . host ( ) ) < < " -U " < < USER_AGENT_STR ;
args < < " -O " < < output . fileName ( ) < < url ;
QEventLoop loop ;
connect ( & process , SIGNAL ( error ( QProcess : : ProcessError ) ) , & loop , SLOT ( quit ( ) ) ) ;
2016-04-23 13:25:01 +02:00
connect ( & process , SIGNAL ( finished ( int , QProcess : : ExitStatus ) ) , & loop , SLOT ( quit ( ) ) ) ;
2014-11-21 17:11:57 +01:00
connect ( & process , SIGNAL ( readyRead ( ) ) , & loop , SLOT ( quit ( ) ) ) ;
QTimer timer ;
timer . setSingleShot ( true ) ;
connect ( & timer , SIGNAL ( timeout ( ) ) , & loop , SLOT ( quit ( ) ) ) ;
const QRegExp httpResponseOK ( " 200 OK$ " ) ;
2016-04-23 13:25:01 +02:00
2014-11-21 17:11:57 +01:00
process . start ( m_binaryWGet , args ) ;
2016-04-23 13:25:01 +02:00
if ( ! process . waitForStarted ( ) )
2014-11-21 17:11:57 +01:00
{
return false ;
}
2017-03-27 23:38:43 +02:00
timer . start ( DOWNLOAD_TIMEOUT ) ;
2014-11-21 17:11:57 +01:00
2016-04-23 13:25:01 +02:00
while ( process . state ( ) ! = QProcess : : NotRunning )
2014-11-21 17:11:57 +01:00
{
loop . exec ( ) ;
const bool bTimeOut = ( ! timer . isActive ( ) ) ;
2016-04-23 13:25:01 +02:00
while ( process . canReadLine ( ) )
2014-11-21 17:11:57 +01:00
{
2017-03-27 23:38:43 +02:00
const QString line = QString : : fromLatin1 ( process . readLine ( ) ) . simplified ( ) ;
2014-11-21 17:11:57 +01:00
log ( line ) ;
}
2016-04-23 13:25:01 +02:00
if ( bTimeOut )
2014-11-21 17:11:57 +01:00
{
qWarning ( " WGet process timed out <-- killing! " ) ;
process . kill ( ) ;
process . waitForFinished ( ) ;
log ( " !!! TIMEOUT !!! " ) ;
return false ;
}
}
2016-04-23 13:25:01 +02:00
2014-11-21 17:11:57 +01:00
timer . stop ( ) ;
timer . disconnect ( & timer , SIGNAL ( timeout ( ) ) , & loop , SLOT ( quit ( ) ) ) ;
log ( QString ( ) . sprintf ( " Exited with code %d " , process . exitCode ( ) ) ) ;
return ( process . exitCode ( ) = = 0 ) & & output . exists ( ) & & output . isFile ( ) ;
}
2017-03-27 23:38:43 +02:00
bool UpdateChecker : : tryContactHost ( const QString & hostname , const int & timeoutMsec )
2016-04-23 13:25:01 +02:00
{
log ( QString ( " Connecting to host: %1 " ) . arg ( hostname ) ) ;
QProcess process ;
init_process ( process , temp_folder ( ) ) ;
QStringList args ;
args < < " -z " < < hostname < < QString : : number ( 80 ) ;
QEventLoop loop ;
connect ( & process , SIGNAL ( error ( QProcess : : ProcessError ) ) , & loop , SLOT ( quit ( ) ) ) ;
connect ( & process , SIGNAL ( finished ( int , QProcess : : ExitStatus ) ) , & loop , SLOT ( quit ( ) ) ) ;
connect ( & process , SIGNAL ( readyRead ( ) ) , & loop , SLOT ( quit ( ) ) ) ;
QTimer timer ;
timer . setSingleShot ( true ) ;
connect ( & timer , SIGNAL ( timeout ( ) ) , & loop , SLOT ( quit ( ) ) ) ;
process . start ( m_binaryNC , args ) ;
if ( ! process . waitForStarted ( ) )
{
return false ;
}
2017-03-27 23:38:43 +02:00
timer . start ( timeoutMsec ) ;
2016-04-23 13:25:01 +02:00
while ( process . state ( ) ! = QProcess : : NotRunning )
{
loop . exec ( ) ;
const bool bTimeOut = ( ! timer . isActive ( ) ) ;
while ( process . canReadLine ( ) )
{
QString line = QString : : fromLatin1 ( process . readLine ( ) ) . simplified ( ) ;
log ( line ) ;
}
if ( bTimeOut )
{
qWarning ( " NC process timed out <-- killing! " ) ;
process . kill ( ) ;
process . waitForFinished ( ) ;
log ( " !!! TIMEOUT !!! " ) ;
return false ;
}
}
timer . stop ( ) ;
timer . disconnect ( & timer , SIGNAL ( timeout ( ) ) , & loop , SLOT ( quit ( ) ) ) ;
if ( process . exitCode ( ) ! = 0 )
{
log ( " Connection has failed! " ) ;
}
log ( QString ( ) . sprintf ( " Exited with code %d " , process . exitCode ( ) ) , " " ) ;
return ( process . exitCode ( ) = = 0 ) ;
}
2014-11-21 17:11:57 +01:00
bool UpdateChecker : : checkSignature ( const QString & file , const QString & signature )
{
2016-04-23 13:25:01 +02:00
if ( QFileInfo ( file ) . absolutePath ( ) . compare ( QFileInfo ( signature ) . absolutePath ( ) , Qt : : CaseInsensitive ) ! = 0 )
2014-11-21 17:11:57 +01:00
{
qWarning ( " CheckSignature: File and signature should be in same folder! " ) ;
return false ;
}
2015-02-01 21:03:28 +01:00
2015-08-31 22:56:39 +02:00
QString keyRingPath ( m_binaryKeys ) ;
bool removeKeyring = false ;
2016-04-23 13:25:01 +02:00
if ( QFileInfo ( file ) . absolutePath ( ) . compare ( QFileInfo ( m_binaryKeys ) . absolutePath ( ) , Qt : : CaseInsensitive ) ! = 0 )
2014-11-21 17:11:57 +01:00
{
2015-08-31 22:56:39 +02:00
keyRingPath = make_temp_file ( QFileInfo ( file ) . absolutePath ( ) , " gpg " ) ;
removeKeyring = true ;
2016-04-23 13:25:01 +02:00
if ( ! QFile : : copy ( m_binaryKeys , keyRingPath ) )
2015-08-31 22:56:39 +02:00
{
qWarning ( " CheckSignature: Failed to copy the key-ring file! " ) ;
return false ;
}
2014-11-21 17:11:57 +01:00
}
QProcess process ;
2014-11-21 17:54:46 +01:00
init_process ( process , QFileInfo ( file ) . absolutePath ( ) ) ;
2014-11-21 17:11:57 +01:00
QEventLoop loop ;
connect ( & process , SIGNAL ( error ( QProcess : : ProcessError ) ) , & loop , SLOT ( quit ( ) ) ) ;
2016-04-23 13:25:01 +02:00
connect ( & process , SIGNAL ( finished ( int , QProcess : : ExitStatus ) ) , & loop , SLOT ( quit ( ) ) ) ;
2014-11-21 17:11:57 +01:00
connect ( & process , SIGNAL ( readyRead ( ) ) , & loop , SLOT ( quit ( ) ) ) ;
2016-04-23 13:25:01 +02:00
2015-08-31 22:56:39 +02:00
process . start ( m_binaryGnuPG , QStringList ( ) < < " --homedir " < < " . " < < " --keyring " < < QFileInfo ( keyRingPath ) . fileName ( ) < < QFileInfo ( signature ) . fileName ( ) < < QFileInfo ( file ) . fileName ( ) ) ;
2014-11-21 17:11:57 +01:00
2016-04-23 13:25:01 +02:00
if ( ! process . waitForStarted ( ) )
2014-11-21 17:11:57 +01:00
{
2016-04-23 13:25:01 +02:00
if ( removeKeyring )
2015-08-31 22:56:39 +02:00
{
remove_file ( keyRingPath ) ;
}
2014-11-21 17:11:57 +01:00
return false ;
}
2016-04-23 13:25:01 +02:00
while ( process . state ( ) = = QProcess : : Running )
2014-11-21 17:11:57 +01:00
{
loop . exec ( ) ;
2016-04-23 13:25:01 +02:00
while ( process . canReadLine ( ) )
2014-11-21 17:11:57 +01:00
{
log ( QString : : fromLatin1 ( process . readLine ( ) ) . simplified ( ) ) ;
}
}
2016-04-23 13:25:01 +02:00
if ( removeKeyring )
2015-08-31 22:56:39 +02:00
{
remove_file ( keyRingPath ) ;
}
2014-11-21 17:11:57 +01:00
log ( QString ( ) . sprintf ( " Exited with code %d " , process . exitCode ( ) ) ) ;
return ( process . exitCode ( ) = = 0 ) ;
}
////////////////////////////////////////////////////////////
// SLOTS
////////////////////////////////////////////////////////////
/*NONE*/
////////////////////////////////////////////////////////////
// EVENTS
////////////////////////////////////////////////////////////
/*NONE*/