xref: /glogg/src/versionchecker.cpp (revision 4fb0346e73d7caa82d42531c8c8681b5eb607728)
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 
22a3f81147SNicolas Bonnefon #include "persistentinfo.h"
23a3f81147SNicolas Bonnefon 
24431d01deSNicolas Bonnefon #include "log.h"
25431d01deSNicolas Bonnefon 
2601bacde4SNicolas Bonnefon #if defined(_WIN64)
2701bacde4SNicolas Bonnefon #  define GLOGG_OS "win64"
2801bacde4SNicolas Bonnefon #elif defined(_WIN32)
2901bacde4SNicolas Bonnefon #  define GLOGG_OS "win32"
3001bacde4SNicolas Bonnefon #elif defined(__APPLE__)
3101bacde4SNicolas Bonnefon #  define GLOGG_OS "OSX"
3201bacde4SNicolas Bonnefon #elif defined(__linux__)
3301bacde4SNicolas Bonnefon #  define GLOGG_OS "linux"
3401bacde4SNicolas Bonnefon #else
3501bacde4SNicolas Bonnefon #  define GLOGG_OS "other"
3601bacde4SNicolas Bonnefon #endif
3701bacde4SNicolas Bonnefon 
38431d01deSNicolas Bonnefon const char* VersionChecker::VERSION_URL =
39431d01deSNicolas Bonnefon     "http://gloggversion.bonnefon.org/latest";
40431d01deSNicolas Bonnefon 
41a3f81147SNicolas Bonnefon const uint64_t VersionChecker::CHECK_INTERVAL_S =
42a3f81147SNicolas Bonnefon     3600 * 24 * 7; /* 7 days */
43a3f81147SNicolas Bonnefon 
4492bcda3bSNicolas Bonnefon namespace {
4592bcda3bSNicolas Bonnefon     bool isVersionNewer( const QString& current, const QString& new_version );
4692bcda3bSNicolas Bonnefon };
4792bcda3bSNicolas Bonnefon 
48a3f81147SNicolas Bonnefon VersionCheckerConfig::VersionCheckerConfig()
49a3f81147SNicolas Bonnefon {
50a3f81147SNicolas Bonnefon     enabled_ = true;
51a3f81147SNicolas Bonnefon     next_deadline_ = 0;
52a3f81147SNicolas Bonnefon }
53a3f81147SNicolas Bonnefon 
54a3f81147SNicolas Bonnefon void VersionCheckerConfig::retrieveFromStorage( QSettings& settings )
55a3f81147SNicolas Bonnefon {
56a3f81147SNicolas Bonnefon     if ( settings.contains( "versionchecker.enabled" ) )
57a3f81147SNicolas Bonnefon         enabled_ = settings.value( "versionchecker.enabled" ).toBool();
58a3f81147SNicolas Bonnefon     if ( settings.contains( "versionchecker.nextDeadline" ) )
59a3f81147SNicolas Bonnefon         next_deadline_ = settings.value( "versionchecker.nextDeadline" ).toLongLong();
60a3f81147SNicolas Bonnefon }
61a3f81147SNicolas Bonnefon 
62a3f81147SNicolas Bonnefon void VersionCheckerConfig::saveToStorage( QSettings& settings ) const
63a3f81147SNicolas Bonnefon {
64a3f81147SNicolas Bonnefon     settings.setValue( "versionchecker.enabled", enabled_ );
65a3f81147SNicolas Bonnefon     settings.setValue( "versionchecker.nextDeadline",
66a3f81147SNicolas Bonnefon             static_cast<long long>( next_deadline_ ) );
67a3f81147SNicolas Bonnefon }
68a3f81147SNicolas Bonnefon 
69431d01deSNicolas Bonnefon VersionChecker::VersionChecker() : QObject(), manager_( this )
70431d01deSNicolas Bonnefon {
71431d01deSNicolas Bonnefon }
72431d01deSNicolas Bonnefon 
73431d01deSNicolas Bonnefon VersionChecker::~VersionChecker()
74431d01deSNicolas Bonnefon {
75431d01deSNicolas Bonnefon }
76431d01deSNicolas Bonnefon 
77431d01deSNicolas Bonnefon void VersionChecker::startCheck()
78431d01deSNicolas Bonnefon {
79431d01deSNicolas Bonnefon     LOG(logDEBUG) << "VersionChecker::startCheck()";
80431d01deSNicolas Bonnefon 
81a3f81147SNicolas Bonnefon     GetPersistentInfo().retrieve( "versionChecker" );
82a3f81147SNicolas Bonnefon 
83a3f81147SNicolas Bonnefon     auto config = Persistent<VersionCheckerConfig>( "versionChecker" );
84a3f81147SNicolas Bonnefon 
85a3f81147SNicolas Bonnefon     if ( config->versionCheckingEnabled() )
86a3f81147SNicolas Bonnefon     {
87a3f81147SNicolas Bonnefon         // Check the deadline has been reached
88a3f81147SNicolas Bonnefon         if ( config->nextDeadline() < std::time( nullptr ) )
89a3f81147SNicolas Bonnefon         {
90431d01deSNicolas Bonnefon             connect( &manager_, SIGNAL( finished( QNetworkReply* ) ),
91431d01deSNicolas Bonnefon                     this, SLOT( downloadFinished( QNetworkReply* ) ) );
92431d01deSNicolas Bonnefon 
93431d01deSNicolas Bonnefon             QNetworkRequest request;
94431d01deSNicolas Bonnefon             request.setUrl( QUrl( VERSION_URL ) );
9501bacde4SNicolas Bonnefon             request.setRawHeader( "User-Agent", "glogg-" GLOGG_VERSION " (" GLOGG_OS ")" );
96431d01deSNicolas Bonnefon             manager_.get( request );
97431d01deSNicolas Bonnefon         }
98a3f81147SNicolas Bonnefon         else
99a3f81147SNicolas Bonnefon         {
100a3f81147SNicolas Bonnefon             LOG(logDEBUG) << "Deadline not reached yet, next check in "
101a3f81147SNicolas Bonnefon                 << std::difftime( config->nextDeadline(), std::time( nullptr ) );
102a3f81147SNicolas Bonnefon         }
103a3f81147SNicolas Bonnefon     }
104a3f81147SNicolas Bonnefon }
105431d01deSNicolas Bonnefon 
106431d01deSNicolas Bonnefon void VersionChecker::downloadFinished( QNetworkReply* reply )
107431d01deSNicolas Bonnefon {
108431d01deSNicolas Bonnefon     LOG(logDEBUG) << "VersionChecker::downloadFinished()";
10992bcda3bSNicolas Bonnefon 
11092bcda3bSNicolas Bonnefon     if ( reply->error() == QNetworkReply::NoError )
11192bcda3bSNicolas Bonnefon     {
112460de700SNicolas Bonnefon         QString new_version = QString( reply->read( 256 ) ).remove( '\n' );
113460de700SNicolas Bonnefon 
11492bcda3bSNicolas Bonnefon         LOG(logDEBUG) << "Latest version is " << new_version.toStdString();
11592bcda3bSNicolas Bonnefon         if ( isVersionNewer( QString( GLOGG_VERSION ), new_version ) )
11692bcda3bSNicolas Bonnefon         {
117460de700SNicolas Bonnefon             LOG(logDEBUG) << "Sending new version notification";
11892bcda3bSNicolas Bonnefon             emit newVersionFound( new_version );
119431d01deSNicolas Bonnefon         }
12092bcda3bSNicolas Bonnefon     }
12192bcda3bSNicolas Bonnefon     else
12292bcda3bSNicolas Bonnefon     {
12392bcda3bSNicolas Bonnefon         LOG(logWARNING) << "Download failed: err " << reply->error();
12492bcda3bSNicolas Bonnefon     }
12592bcda3bSNicolas Bonnefon 
12692bcda3bSNicolas Bonnefon     reply->deleteLater();
127a3f81147SNicolas Bonnefon 
128a3f81147SNicolas Bonnefon     // Extend the deadline
129a3f81147SNicolas Bonnefon     auto config = Persistent<VersionCheckerConfig>( "versionChecker" );
130a3f81147SNicolas Bonnefon 
131a3f81147SNicolas Bonnefon     config->setNextDeadline( std::time( nullptr ) + CHECK_INTERVAL_S );
132a3f81147SNicolas Bonnefon 
133a3f81147SNicolas Bonnefon     GetPersistentInfo().save( "versionChecker" );
13492bcda3bSNicolas Bonnefon }
13592bcda3bSNicolas Bonnefon 
13692bcda3bSNicolas Bonnefon namespace {
13792bcda3bSNicolas Bonnefon     bool isVersionNewer( const QString& current, const QString& new_version )
13892bcda3bSNicolas Bonnefon     {
139*4fb0346eSAnton Filimonov         QRegularExpression version_regex( "(\\d+)\\.(\\d+)\\.(\\d+)(-(\\S+))?" );
140460de700SNicolas Bonnefon 
141460de700SNicolas Bonnefon         // Main version is the three first digits
142460de700SNicolas Bonnefon         // Add is the part after '-' if there
143460de700SNicolas Bonnefon         unsigned current_main_version = 0;
144460de700SNicolas Bonnefon         unsigned current_add_version = 0;
145460de700SNicolas Bonnefon         unsigned new_main_version = 0;
146460de700SNicolas Bonnefon         unsigned new_add_version = 0;
147460de700SNicolas Bonnefon 
148*4fb0346eSAnton Filimonov         QRegularExpressionMatch currentMatch = version_regex.match( current );
149*4fb0346eSAnton Filimonov         if ( currentMatch.hasMatch() )
150460de700SNicolas Bonnefon         {
151*4fb0346eSAnton Filimonov             current_main_version = currentMatch.captured(3).toInt()
152*4fb0346eSAnton Filimonov                 + currentMatch.captured(2).toInt() * 100
153*4fb0346eSAnton Filimonov                 + currentMatch.captured(1).toInt() * 10000;
154*4fb0346eSAnton Filimonov             current_add_version = currentMatch.captured(5).isEmpty() ? 0 : 1;
155460de700SNicolas Bonnefon         }
156460de700SNicolas Bonnefon 
157*4fb0346eSAnton Filimonov         QRegularExpressionMatch newMatch = version_regex.match( new_version );
158460de700SNicolas Bonnefon         if ( version_regex.indexIn( new_version ) != -1 )
159460de700SNicolas Bonnefon         {
160*4fb0346eSAnton Filimonov             new_main_version = newMatch.captured(3).toInt()
161*4fb0346eSAnton Filimonov                 + newMatch.captured(2).toInt() * 100
162*4fb0346eSAnton Filimonov                 + newMatch.captured(1).toInt() * 10000;
163*4fb0346eSAnton Filimonov             new_add_version = newMatch.captured(5).isEmpty() ? 0 : 1;
164460de700SNicolas Bonnefon         }
165460de700SNicolas Bonnefon 
166460de700SNicolas Bonnefon         LOG(logDEBUG) << "Current version: " << current_main_version;
167460de700SNicolas Bonnefon         LOG(logDEBUG) << "New version: " << new_main_version;
168460de700SNicolas Bonnefon 
169460de700SNicolas Bonnefon         // We only consider the main part for testing for now
170460de700SNicolas Bonnefon         return new_main_version > current_main_version;
17192bcda3bSNicolas Bonnefon     }
17292bcda3bSNicolas Bonnefon };
173