285 lines
9.0 KiB
C++
Executable File
285 lines
9.0 KiB
C++
Executable File
// This file is part of RSS Guard.
|
|
//
|
|
// Copyright (C) 2011-2016 by Martin Rotter <rotter.martinos@gmail.com>
|
|
//
|
|
// RSS Guard 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.
|
|
//
|
|
// RSS Guard 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 RSS Guard. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#include "miscellaneous/systemfactory.h"
|
|
|
|
#include "network-web/networkfactory.h"
|
|
#include "gui/dialogs/formmain.h"
|
|
#include "miscellaneous/application.h"
|
|
#include "miscellaneous/systemfactory.h"
|
|
|
|
#if defined(Q_OS_WIN)
|
|
#include <QSettings>
|
|
#endif
|
|
|
|
#include <QString>
|
|
#include <QFile>
|
|
#include <QDomDocument>
|
|
#include <QDomElement>
|
|
#include <QDomAttr>
|
|
#include <QFuture>
|
|
#include <QFutureWatcher>
|
|
#include <QtConcurrent/QtConcurrentRun>
|
|
|
|
|
|
typedef QPair<UpdateInfo, QNetworkReply::NetworkError> UpdateCheck;
|
|
|
|
SystemFactory::SystemFactory(QObject *parent) : QObject(parent) {
|
|
}
|
|
|
|
SystemFactory::~SystemFactory() {
|
|
}
|
|
|
|
SystemFactory::AutoStartStatus SystemFactory::getAutoStartStatus() const {
|
|
// User registry way to auto-start the application on Windows.
|
|
#if defined(Q_OS_WIN)
|
|
QSettings registry_key(QSL("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run"),
|
|
QSettings::NativeFormat);
|
|
const bool autostart_enabled = registry_key.value(QSL(APP_LOW_NAME),
|
|
QString()).toString().replace(QL1C('\\'),
|
|
QL1C('/')) ==
|
|
Application::applicationFilePath();
|
|
|
|
if (autostart_enabled) {
|
|
return SystemFactory::Enabled;
|
|
}
|
|
else {
|
|
return SystemFactory::Disabled;
|
|
}
|
|
|
|
// Use proper freedesktop.org way to auto-start the application on Linux.
|
|
// INFO: http://standards.freedesktop.org/autostart-spec/latest/
|
|
#elif defined(Q_OS_LINUX)
|
|
const QString desktop_file_location = getAutostartDesktopFileLocation();
|
|
|
|
// No correct path was found.
|
|
if (desktop_file_location.isEmpty()) {
|
|
qWarning("Searching for auto-start function status failed. HOME variable not found.");
|
|
return SystemFactory::Unavailable;
|
|
}
|
|
|
|
// We found correct path, now check if file exists and return correct status.
|
|
if (QFile::exists(desktop_file_location)) {
|
|
return SystemFactory::Enabled;
|
|
}
|
|
else {
|
|
return SystemFactory::Disabled;
|
|
}
|
|
|
|
// Disable auto-start functionality on unsupported platforms.
|
|
#else
|
|
return SystemFactory::Unavailable;
|
|
#endif
|
|
}
|
|
|
|
#if defined(Q_OS_LINUX)
|
|
QString SystemFactory::getAutostartDesktopFileLocation() const {
|
|
const QString xdg_config_path(qgetenv("XDG_CONFIG_HOME"));
|
|
QString desktop_file_location;
|
|
|
|
if (!xdg_config_path.isEmpty()) {
|
|
// XDG_CONFIG_HOME variable is specified. Look for .desktop file
|
|
// in 'autostart' subdirectory.
|
|
desktop_file_location = xdg_config_path + QSL("/autostart/") + APP_DESKTOP_ENTRY_FILE;
|
|
}
|
|
else {
|
|
// Desired variable is not set, look for the default 'autostart' subdirectory.
|
|
const QString home_directory(qgetenv("HOME"));
|
|
|
|
if (!home_directory.isEmpty()) {
|
|
// Home directory exists. Check if target .desktop file exists and
|
|
// return according status.
|
|
desktop_file_location = home_directory + QSL("/.config/autostart/") + APP_DESKTOP_ENTRY_FILE;
|
|
}
|
|
}
|
|
|
|
// No location found, return empty string.
|
|
return desktop_file_location;
|
|
}
|
|
#endif
|
|
|
|
bool SystemFactory::setAutoStartStatus(const AutoStartStatus &new_status) {
|
|
const SystemFactory::AutoStartStatus current_status = SystemFactory::getAutoStartStatus();
|
|
|
|
// Auto-start feature is not even available, exit.
|
|
if (current_status == SystemFactory::Unavailable) {
|
|
return false;
|
|
}
|
|
|
|
#if defined(Q_OS_WIN)
|
|
QSettings registry_key(QSL("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run"), QSettings::NativeFormat);
|
|
|
|
switch (new_status) {
|
|
case SystemFactory::Enabled:
|
|
registry_key.setValue(APP_LOW_NAME,
|
|
Application::applicationFilePath().replace(QL1C('/'), QL1C('\\')));
|
|
return true;
|
|
|
|
case SystemFactory::Disabled:
|
|
registry_key.remove(APP_LOW_NAME);
|
|
return true;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
#elif defined(Q_OS_LINUX)
|
|
// Note that we expect here that no other program uses
|
|
// "rssguard.desktop" desktop file.
|
|
switch (new_status) {
|
|
case SystemFactory::Enabled:
|
|
QFile::link(QString(APP_DESKTOP_ENTRY_PATH) + '/' + APP_DESKTOP_ENTRY_FILE, getAutostartDesktopFileLocation());
|
|
return true;
|
|
|
|
case SystemFactory::Disabled:
|
|
QFile::remove(getAutostartDesktopFileLocation());
|
|
return true;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
#if defined(Q_OS_WIN)
|
|
bool SystemFactory::removeTrolltechJunkRegistryKeys() {
|
|
if (qApp->settings()->value(GROUP(General), SETTING(General::RemoveTrolltechJunk)).toBool()) {
|
|
QSettings registry_key(QSL("HKEY_CURRENT_USER\\Software\\TrollTech"), QSettings::NativeFormat);
|
|
|
|
registry_key.remove(QSL(""));
|
|
registry_key.sync();
|
|
|
|
return registry_key.status() == QSettings::NoError;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
QString SystemFactory::getUsername() const {
|
|
QString name = qgetenv("USER");
|
|
|
|
if (name.isEmpty()) {
|
|
name = qgetenv("USERNAME");
|
|
}
|
|
|
|
if (name.isEmpty()) {
|
|
name = tr("anonymous");
|
|
}
|
|
|
|
return name;
|
|
}
|
|
|
|
QPair<UpdateInfo, QNetworkReply::NetworkError> SystemFactory::checkForUpdates() const {
|
|
QPair<UpdateInfo, QNetworkReply::NetworkError> result;
|
|
QByteArray releases_xml;
|
|
QByteArray changelog;
|
|
|
|
result.second = NetworkFactory::performNetworkOperation(RELEASES_LIST, DOWNLOAD_TIMEOUT, QByteArray(), QString(),
|
|
releases_xml, QNetworkAccessManager::GetOperation).first;
|
|
NetworkFactory::performNetworkOperation(CHANGELOG, DOWNLOAD_TIMEOUT, QByteArray(), QString(), changelog,
|
|
QNetworkAccessManager::GetOperation);
|
|
|
|
if (result.second == QNetworkReply::NoError) {
|
|
result.first = parseUpdatesFile(releases_xml, changelog);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool SystemFactory::isVersionNewer(const QString &new_version, const QString &base_version) {
|
|
QStringList base_version_tkn = base_version.split(QL1C('.'));
|
|
QStringList new_version_tkn = new_version.split(QL1C('.'));
|
|
|
|
while (!base_version_tkn.isEmpty() && !new_version_tkn.isEmpty()) {
|
|
const int base_number = base_version_tkn.takeFirst().toInt();
|
|
const int new_number = new_version_tkn.takeFirst().toInt();
|
|
|
|
if (new_number > base_number) {
|
|
// New version is indeed higher thatn current version.
|
|
return true;
|
|
}
|
|
else if (new_number < base_number) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Versions are either the same or they have unequal sizes.
|
|
if (base_version_tkn.isEmpty() && new_version_tkn.isEmpty()) {
|
|
// Versions are the same.
|
|
return false;
|
|
}
|
|
else {
|
|
if (new_version_tkn.isEmpty()) {
|
|
return false;
|
|
}
|
|
else {
|
|
return new_version_tkn.join(QString()).toInt() > 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool SystemFactory::isVersionEqualOrNewer(const QString &new_version, const QString &base_version) {
|
|
return new_version == base_version || isVersionNewer(new_version, base_version);
|
|
}
|
|
|
|
UpdateInfo SystemFactory::parseUpdatesFile(const QByteArray &updates_file, const QByteArray &changelog) const {
|
|
UpdateInfo update;
|
|
QDomDocument document; document.setContent(updates_file, false);
|
|
const QDomNodeList releases = document.elementsByTagName(QSL("release"));
|
|
|
|
if (releases.size() == 1) {
|
|
QDomElement rel_elem = releases.at(0).toElement();
|
|
|
|
update.m_availableVersion = rel_elem.attributes().namedItem(QSL("version")).toAttr().value();
|
|
update.m_changes = QString::fromUtf8(changelog);
|
|
|
|
QDomNodeList urls = rel_elem.elementsByTagName(QSL("url"));
|
|
|
|
for (int j = 0; j < urls.size(); j++) {
|
|
UpdateUrl url;
|
|
QDomElement url_elem = urls.at(j).toElement();
|
|
|
|
url.m_fileUrl = url_elem.text();
|
|
url.m_os = url_elem.attributes().namedItem(QSL("os")).toAttr().value();
|
|
url.m_platform = url_elem.attributes().namedItem(QSL("platform")).toAttr().value();
|
|
|
|
update.m_urls.insert(url.m_os, url);
|
|
}
|
|
}
|
|
else {
|
|
update.m_availableVersion = QString();
|
|
}
|
|
|
|
|
|
return update;
|
|
}
|
|
|
|
void SystemFactory::checkForUpdatesOnStartup() {
|
|
const UpdateCheck updates = checkForUpdates();
|
|
|
|
if (updates.second == QNetworkReply::NoError && isVersionNewer(updates.first.m_availableVersion,
|
|
APP_VERSION)) {
|
|
qApp->showGuiMessage(tr("New version available"),
|
|
tr("Click the bubble for more information."),
|
|
QSystemTrayIcon::Information,
|
|
NULL, true, QIcon(), qApp->mainForm(), SLOT(showUpdates()));
|
|
}
|
|
}
|