/*
* Copyright (C) 2014 Nicolas Bonnefon and other contributors
*
* This file is part of glogg.
*
* glogg is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* glogg 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with glogg. If not, see .
*/
#include "versionchecker.h"
#include "persistentinfo.h"
#include "log.h"
#if defined(_WIN64)
# define GLOGG_OS "win64"
#elif defined(_WIN32)
# define GLOGG_OS "win32"
#elif defined(__APPLE__)
# define GLOGG_OS "OSX"
#elif defined(__linux__)
# define GLOGG_OS "linux"
#else
# define GLOGG_OS "other"
#endif
const char* VersionChecker::VERSION_URL =
"http://gloggversion.bonnefon.org/latest";
const uint64_t VersionChecker::CHECK_INTERVAL_S =
3600 * 24 * 7; /* 7 days */
namespace {
bool isVersionNewer( const QString& current, const QString& new_version );
};
VersionCheckerConfig::VersionCheckerConfig()
{
enabled_ = true;
next_deadline_ = 0;
}
void VersionCheckerConfig::retrieveFromStorage( QSettings& settings )
{
if ( settings.contains( "versionchecker.enabled" ) )
enabled_ = settings.value( "versionchecker.enabled" ).toBool();
if ( settings.contains( "versionchecker.nextDeadline" ) )
next_deadline_ = settings.value( "versionchecker.nextDeadline" ).toLongLong();
}
void VersionCheckerConfig::saveToStorage( QSettings& settings ) const
{
settings.setValue( "versionchecker.enabled", enabled_ );
settings.setValue( "versionchecker.nextDeadline",
static_cast( next_deadline_ ) );
}
VersionChecker::VersionChecker() : QObject(), manager_( this )
{
}
VersionChecker::~VersionChecker()
{
}
void VersionChecker::startCheck()
{
LOG(logDEBUG) << "VersionChecker::startCheck()";
GetPersistentInfo().retrieve( "versionChecker" );
auto config = Persistent( "versionChecker" );
if ( config->versionCheckingEnabled() )
{
// Check the deadline has been reached
if ( config->nextDeadline() < std::time( nullptr ) )
{
connect( &manager_, SIGNAL( finished( QNetworkReply* ) ),
this, SLOT( downloadFinished( QNetworkReply* ) ) );
QNetworkRequest request;
request.setUrl( QUrl( VERSION_URL ) );
request.setRawHeader( "User-Agent", "glogg-" GLOGG_VERSION " (" GLOGG_OS ")" );
manager_.get( request );
}
else
{
LOG(logDEBUG) << "Deadline not reached yet, next check in "
<< std::difftime( config->nextDeadline(), std::time( nullptr ) );
}
}
}
void VersionChecker::downloadFinished( QNetworkReply* reply )
{
LOG(logDEBUG) << "VersionChecker::downloadFinished()";
if ( reply->error() == QNetworkReply::NoError )
{
QString new_version = QString( reply->read( 256 ) ).remove( '\n' );
LOG(logDEBUG) << "Latest version is " << new_version.toStdString();
if ( isVersionNewer( QString( GLOGG_VERSION ), new_version ) )
{
LOG(logDEBUG) << "Sending new version notification";
emit newVersionFound( new_version );
}
}
else
{
LOG(logWARNING) << "Download failed: err " << reply->error();
}
reply->deleteLater();
// Extend the deadline
auto config = Persistent( "versionChecker" );
config->setNextDeadline( std::time( nullptr ) + CHECK_INTERVAL_S );
GetPersistentInfo().save( "versionChecker" );
}
namespace {
bool isVersionNewer( const QString& current, const QString& new_version )
{
QRegularExpression version_regex( "(\\d+)\\.(\\d+)\\.(\\d+)(-(\\S+))?" );
// Main version is the three first digits
// Add is the part after '-' if there
unsigned current_main_version = 0;
unsigned current_add_version = 0;
unsigned new_main_version = 0;
unsigned new_add_version = 0;
QRegularExpressionMatch currentMatch = version_regex.match( current );
if ( currentMatch.hasMatch() )
{
current_main_version = currentMatch.captured(3).toInt()
+ currentMatch.captured(2).toInt() * 100
+ currentMatch.captured(1).toInt() * 10000;
current_add_version = currentMatch.captured(5).isEmpty() ? 0 : 1;
}
QRegularExpressionMatch newMatch = version_regex.match( new_version );
if ( version_regex.indexIn( new_version ) != -1 )
{
new_main_version = newMatch.captured(3).toInt()
+ newMatch.captured(2).toInt() * 100
+ newMatch.captured(1).toInt() * 10000;
new_add_version = newMatch.captured(5).isEmpty() ? 0 : 1;
}
LOG(logDEBUG) << "Current version: " << current_main_version;
LOG(logDEBUG) << "New version: " << new_main_version;
// We only consider the main part for testing for now
return new_main_version > current_main_version;
}
};