1 /* 2 * Copyright (C) 2014 Nicolas Bonnefon and other contributors 3 * 4 * This file is part of glogg. 5 * 6 * glogg is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * glogg is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with glogg. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "versionchecker.h" 21 22 #include "persistentinfo.h" 23 24 #include "log.h" 25 26 const char* VersionChecker::VERSION_URL = 27 "http://gloggversion.bonnefon.org/latest"; 28 29 const uint64_t VersionChecker::CHECK_INTERVAL_S = 30 3600 * 24 * 7; /* 7 days */ 31 32 namespace { 33 bool isVersionNewer( const QString& current, const QString& new_version ); 34 }; 35 36 VersionCheckerConfig::VersionCheckerConfig() 37 { 38 enabled_ = true; 39 next_deadline_ = 0; 40 } 41 42 void VersionCheckerConfig::retrieveFromStorage( QSettings& settings ) 43 { 44 if ( settings.contains( "versionchecker.enabled" ) ) 45 enabled_ = settings.value( "versionchecker.enabled" ).toBool(); 46 if ( settings.contains( "versionchecker.nextDeadline" ) ) 47 next_deadline_ = settings.value( "versionchecker.nextDeadline" ).toLongLong(); 48 } 49 50 void VersionCheckerConfig::saveToStorage( QSettings& settings ) const 51 { 52 settings.setValue( "versionchecker.enabled", enabled_ ); 53 settings.setValue( "versionchecker.nextDeadline", 54 static_cast<long long>( next_deadline_ ) ); 55 } 56 57 VersionChecker::VersionChecker() : QObject(), manager_( this ) 58 { 59 } 60 61 VersionChecker::~VersionChecker() 62 { 63 } 64 65 void VersionChecker::startCheck() 66 { 67 LOG(logDEBUG) << "VersionChecker::startCheck()"; 68 69 GetPersistentInfo().retrieve( "versionChecker" ); 70 71 auto config = Persistent<VersionCheckerConfig>( "versionChecker" ); 72 73 if ( config->versionCheckingEnabled() ) 74 { 75 // Check the deadline has been reached 76 if ( config->nextDeadline() < std::time( nullptr ) ) 77 { 78 connect( &manager_, SIGNAL( finished( QNetworkReply* ) ), 79 this, SLOT( downloadFinished( QNetworkReply* ) ) ); 80 81 QNetworkRequest request; 82 request.setUrl( QUrl( VERSION_URL ) ); 83 request.setRawHeader( "User-Agent", "glogg-" GLOGG_VERSION ); 84 manager_.get( request ); 85 } 86 else 87 { 88 LOG(logDEBUG) << "Deadline not reached yet, next check in " 89 << std::difftime( config->nextDeadline(), std::time( nullptr ) ); 90 } 91 } 92 } 93 94 void VersionChecker::downloadFinished( QNetworkReply* reply ) 95 { 96 LOG(logDEBUG) << "VersionChecker::downloadFinished()"; 97 98 if ( reply->error() == QNetworkReply::NoError ) 99 { 100 QString new_version = QString( reply->read( 256 ) ).remove( '\n' ); 101 102 LOG(logDEBUG) << "Latest version is " << new_version.toStdString(); 103 if ( isVersionNewer( QString( GLOGG_VERSION ), new_version ) ) 104 { 105 LOG(logDEBUG) << "Sending new version notification"; 106 emit newVersionFound( new_version ); 107 } 108 } 109 else 110 { 111 LOG(logWARNING) << "Download failed: err " << reply->error(); 112 } 113 114 reply->deleteLater(); 115 116 // Extend the deadline 117 auto config = Persistent<VersionCheckerConfig>( "versionChecker" ); 118 119 config->setNextDeadline( std::time( nullptr ) + CHECK_INTERVAL_S ); 120 121 GetPersistentInfo().save( "versionChecker" ); 122 } 123 124 namespace { 125 bool isVersionNewer( const QString& current, const QString& new_version ) 126 { 127 QRegExp version_regex( "(\\d+)\\.(\\d+)\\.(\\d+)(-(\\S+))?", 128 Qt::CaseSensitive, 129 QRegExp::RegExp2 ); 130 131 // Main version is the three first digits 132 // Add is the part after '-' if there 133 unsigned current_main_version = 0; 134 unsigned current_add_version = 0; 135 unsigned new_main_version = 0; 136 unsigned new_add_version = 0; 137 138 if ( version_regex.indexIn( current ) != -1 ) 139 { 140 current_main_version = version_regex.cap(3).toInt() 141 + version_regex.cap(2).toInt() * 100 142 + version_regex.cap(1).toInt() * 10000; 143 current_add_version = version_regex.cap(5).isEmpty() ? 0 : 1; 144 } 145 146 if ( version_regex.indexIn( new_version ) != -1 ) 147 { 148 new_main_version = version_regex.cap(3).toInt() 149 + version_regex.cap(2).toInt() * 100 150 + version_regex.cap(1).toInt() * 10000; 151 new_add_version = version_regex.cap(5).isEmpty() ? 0 : 1; 152 } 153 154 LOG(logDEBUG) << "Current version: " << current_main_version; 155 LOG(logDEBUG) << "New version: " << new_main_version; 156 157 // We only consider the main part for testing for now 158 return new_main_version > current_main_version; 159 } 160 }; 161