1431d01deSNicolas Bonnefon /* 2431d01deSNicolas Bonnefon * Copyright (C) 2014 Nicolas Bonnefon and other contributors 3431d01deSNicolas Bonnefon * 4431d01deSNicolas Bonnefon * This file is part of glogg. 5431d01deSNicolas Bonnefon * 6431d01deSNicolas Bonnefon * glogg is free software: you can redistribute it and/or modify 7431d01deSNicolas Bonnefon * it under the terms of the GNU General Public License as published by 8431d01deSNicolas Bonnefon * the Free Software Foundation, either version 3 of the License, or 9431d01deSNicolas Bonnefon * (at your option) any later version. 10431d01deSNicolas Bonnefon * 11431d01deSNicolas Bonnefon * glogg is distributed in the hope that it will be useful, 12431d01deSNicolas Bonnefon * but WITHOUT ANY WARRANTY; without even the implied warranty of 13431d01deSNicolas Bonnefon * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14431d01deSNicolas Bonnefon * GNU General Public License for more details. 15431d01deSNicolas Bonnefon * 16431d01deSNicolas Bonnefon * You should have received a copy of the GNU General Public License 17431d01deSNicolas Bonnefon * along with glogg. If not, see <http://www.gnu.org/licenses/>. 18431d01deSNicolas Bonnefon */ 19431d01deSNicolas Bonnefon 20431d01deSNicolas Bonnefon #include "versionchecker.h" 21431d01deSNicolas Bonnefon 22*a3f81147SNicolas Bonnefon #include "persistentinfo.h" 23*a3f81147SNicolas Bonnefon 24431d01deSNicolas Bonnefon #include "log.h" 25431d01deSNicolas Bonnefon 26431d01deSNicolas Bonnefon const char* VersionChecker::VERSION_URL = 27431d01deSNicolas Bonnefon "http://gloggversion.bonnefon.org/latest"; 28431d01deSNicolas Bonnefon 29*a3f81147SNicolas Bonnefon const uint64_t VersionChecker::CHECK_INTERVAL_S = 30*a3f81147SNicolas Bonnefon 3600 * 24 * 7; /* 7 days */ 31*a3f81147SNicolas Bonnefon 3292bcda3bSNicolas Bonnefon namespace { 3392bcda3bSNicolas Bonnefon bool isVersionNewer( const QString& current, const QString& new_version ); 3492bcda3bSNicolas Bonnefon }; 3592bcda3bSNicolas Bonnefon 36*a3f81147SNicolas Bonnefon VersionCheckerConfig::VersionCheckerConfig() 37*a3f81147SNicolas Bonnefon { 38*a3f81147SNicolas Bonnefon enabled_ = true; 39*a3f81147SNicolas Bonnefon next_deadline_ = 0; 40*a3f81147SNicolas Bonnefon } 41*a3f81147SNicolas Bonnefon 42*a3f81147SNicolas Bonnefon void VersionCheckerConfig::retrieveFromStorage( QSettings& settings ) 43*a3f81147SNicolas Bonnefon { 44*a3f81147SNicolas Bonnefon if ( settings.contains( "versionchecker.enabled" ) ) 45*a3f81147SNicolas Bonnefon enabled_ = settings.value( "versionchecker.enabled" ).toBool(); 46*a3f81147SNicolas Bonnefon if ( settings.contains( "versionchecker.nextDeadline" ) ) 47*a3f81147SNicolas Bonnefon next_deadline_ = settings.value( "versionchecker.nextDeadline" ).toLongLong(); 48*a3f81147SNicolas Bonnefon } 49*a3f81147SNicolas Bonnefon 50*a3f81147SNicolas Bonnefon void VersionCheckerConfig::saveToStorage( QSettings& settings ) const 51*a3f81147SNicolas Bonnefon { 52*a3f81147SNicolas Bonnefon settings.setValue( "versionchecker.enabled", enabled_ ); 53*a3f81147SNicolas Bonnefon settings.setValue( "versionchecker.nextDeadline", 54*a3f81147SNicolas Bonnefon static_cast<long long>( next_deadline_ ) ); 55*a3f81147SNicolas Bonnefon } 56*a3f81147SNicolas Bonnefon 57431d01deSNicolas Bonnefon VersionChecker::VersionChecker() : QObject(), manager_( this ) 58431d01deSNicolas Bonnefon { 59431d01deSNicolas Bonnefon } 60431d01deSNicolas Bonnefon 61431d01deSNicolas Bonnefon VersionChecker::~VersionChecker() 62431d01deSNicolas Bonnefon { 63431d01deSNicolas Bonnefon } 64431d01deSNicolas Bonnefon 65431d01deSNicolas Bonnefon void VersionChecker::startCheck() 66431d01deSNicolas Bonnefon { 67431d01deSNicolas Bonnefon LOG(logDEBUG) << "VersionChecker::startCheck()"; 68431d01deSNicolas Bonnefon 69*a3f81147SNicolas Bonnefon GetPersistentInfo().retrieve( "versionChecker" ); 70*a3f81147SNicolas Bonnefon 71*a3f81147SNicolas Bonnefon auto config = Persistent<VersionCheckerConfig>( "versionChecker" ); 72*a3f81147SNicolas Bonnefon 73*a3f81147SNicolas Bonnefon if ( config->versionCheckingEnabled() ) 74*a3f81147SNicolas Bonnefon { 75*a3f81147SNicolas Bonnefon // Check the deadline has been reached 76*a3f81147SNicolas Bonnefon if ( config->nextDeadline() < std::time( nullptr ) ) 77*a3f81147SNicolas Bonnefon { 78431d01deSNicolas Bonnefon connect( &manager_, SIGNAL( finished( QNetworkReply* ) ), 79431d01deSNicolas Bonnefon this, SLOT( downloadFinished( QNetworkReply* ) ) ); 80431d01deSNicolas Bonnefon 81431d01deSNicolas Bonnefon QNetworkRequest request; 82431d01deSNicolas Bonnefon request.setUrl( QUrl( VERSION_URL ) ); 83431d01deSNicolas Bonnefon request.setRawHeader( "User-Agent", "glogg-" GLOGG_VERSION ); 84431d01deSNicolas Bonnefon manager_.get( request ); 85431d01deSNicolas Bonnefon } 86*a3f81147SNicolas Bonnefon else 87*a3f81147SNicolas Bonnefon { 88*a3f81147SNicolas Bonnefon LOG(logDEBUG) << "Deadline not reached yet, next check in " 89*a3f81147SNicolas Bonnefon << std::difftime( config->nextDeadline(), std::time( nullptr ) ); 90*a3f81147SNicolas Bonnefon } 91*a3f81147SNicolas Bonnefon } 92*a3f81147SNicolas Bonnefon } 93431d01deSNicolas Bonnefon 94431d01deSNicolas Bonnefon void VersionChecker::downloadFinished( QNetworkReply* reply ) 95431d01deSNicolas Bonnefon { 96431d01deSNicolas Bonnefon LOG(logDEBUG) << "VersionChecker::downloadFinished()"; 9792bcda3bSNicolas Bonnefon 9892bcda3bSNicolas Bonnefon if ( reply->error() == QNetworkReply::NoError ) 9992bcda3bSNicolas Bonnefon { 100460de700SNicolas Bonnefon QString new_version = QString( reply->read( 256 ) ).remove( '\n' ); 101460de700SNicolas Bonnefon 10292bcda3bSNicolas Bonnefon LOG(logDEBUG) << "Latest version is " << new_version.toStdString(); 10392bcda3bSNicolas Bonnefon if ( isVersionNewer( QString( GLOGG_VERSION ), new_version ) ) 10492bcda3bSNicolas Bonnefon { 105460de700SNicolas Bonnefon LOG(logDEBUG) << "Sending new version notification"; 10692bcda3bSNicolas Bonnefon emit newVersionFound( new_version ); 107431d01deSNicolas Bonnefon } 10892bcda3bSNicolas Bonnefon } 10992bcda3bSNicolas Bonnefon else 11092bcda3bSNicolas Bonnefon { 11192bcda3bSNicolas Bonnefon LOG(logWARNING) << "Download failed: err " << reply->error(); 11292bcda3bSNicolas Bonnefon } 11392bcda3bSNicolas Bonnefon 11492bcda3bSNicolas Bonnefon reply->deleteLater(); 115*a3f81147SNicolas Bonnefon 116*a3f81147SNicolas Bonnefon // Extend the deadline 117*a3f81147SNicolas Bonnefon auto config = Persistent<VersionCheckerConfig>( "versionChecker" ); 118*a3f81147SNicolas Bonnefon 119*a3f81147SNicolas Bonnefon config->setNextDeadline( std::time( nullptr ) + CHECK_INTERVAL_S ); 120*a3f81147SNicolas Bonnefon 121*a3f81147SNicolas Bonnefon GetPersistentInfo().save( "versionChecker" ); 12292bcda3bSNicolas Bonnefon } 12392bcda3bSNicolas Bonnefon 12492bcda3bSNicolas Bonnefon namespace { 12592bcda3bSNicolas Bonnefon bool isVersionNewer( const QString& current, const QString& new_version ) 12692bcda3bSNicolas Bonnefon { 127460de700SNicolas Bonnefon QRegExp version_regex( "(\\d+)\\.(\\d+)\\.(\\d+)(-(\\S+))?", 128460de700SNicolas Bonnefon Qt::CaseSensitive, 129460de700SNicolas Bonnefon QRegExp::RegExp2 ); 130460de700SNicolas Bonnefon 131460de700SNicolas Bonnefon // Main version is the three first digits 132460de700SNicolas Bonnefon // Add is the part after '-' if there 133460de700SNicolas Bonnefon unsigned current_main_version = 0; 134460de700SNicolas Bonnefon unsigned current_add_version = 0; 135460de700SNicolas Bonnefon unsigned new_main_version = 0; 136460de700SNicolas Bonnefon unsigned new_add_version = 0; 137460de700SNicolas Bonnefon 138460de700SNicolas Bonnefon if ( version_regex.indexIn( current ) != -1 ) 139460de700SNicolas Bonnefon { 140460de700SNicolas Bonnefon current_main_version = version_regex.cap(3).toInt() 141460de700SNicolas Bonnefon + version_regex.cap(2).toInt() * 100 142460de700SNicolas Bonnefon + version_regex.cap(1).toInt() * 10000; 143460de700SNicolas Bonnefon current_add_version = version_regex.cap(5).isEmpty() ? 0 : 1; 144460de700SNicolas Bonnefon } 145460de700SNicolas Bonnefon 146460de700SNicolas Bonnefon if ( version_regex.indexIn( new_version ) != -1 ) 147460de700SNicolas Bonnefon { 148460de700SNicolas Bonnefon new_main_version = version_regex.cap(3).toInt() 149460de700SNicolas Bonnefon + version_regex.cap(2).toInt() * 100 150460de700SNicolas Bonnefon + version_regex.cap(1).toInt() * 10000; 151460de700SNicolas Bonnefon new_add_version = version_regex.cap(5).isEmpty() ? 0 : 1; 152460de700SNicolas Bonnefon } 153460de700SNicolas Bonnefon 154460de700SNicolas Bonnefon LOG(logDEBUG) << "Current version: " << current_main_version; 155460de700SNicolas Bonnefon LOG(logDEBUG) << "New version: " << new_main_version; 156460de700SNicolas Bonnefon 157460de700SNicolas Bonnefon // We only consider the main part for testing for now 158460de700SNicolas Bonnefon return new_main_version > current_main_version; 15992bcda3bSNicolas Bonnefon } 16092bcda3bSNicolas Bonnefon }; 161