From dc9f145a247808cadc55c3141f97560fae8abdc3 Mon Sep 17 00:00:00 2001 From: Daniel Molkentin Date: Wed, 15 Jan 2014 11:08:42 +0100 Subject: [PATCH] New Updater for Windows, passive notification on Linux, Sparkle on Mac --- VERSION.cmake | 1 - src/CMakeLists.txt | 50 ++- src/main.cpp | 26 +- src/mirall/application.cpp | 20 +- src/mirall/cocoainitializer.h | 28 ++ src/mirall/cocoainitializer_mac.mm | 39 +++ src/mirall/generalsettings.cpp | 18 +- src/mirall/generalsettings.h | 1 + src/mirall/generalsettings.ui | 50 ++- src/mirall/genericupdater.cpp | 355 +++++++++++++++++++++ src/mirall/genericupdater.h | 80 +++++ src/mirall/mirallconfigfile.cpp | 17 +- src/mirall/mirallconfigfile.h | 16 +- src/mirall/networkjobs.cpp | 2 + src/mirall/sparkleupdater.h | 37 +++ src/mirall/sparkleupdater_mac.mm | 63 ++++ src/mirall/updatedetector.cpp | 189 ----------- src/mirall/updatedetector.h | 55 ---- src/mirall/{occinfo.cpp => updateinfo.cpp} | 64 ++-- src/mirall/{occinfo.h => updateinfo.h} | 23 +- src/mirall/updater.cpp | 40 +++ src/mirall/updater.h | 42 +++ src/mirall/utility.cpp | 9 + src/mirall/utility.h | 1 + src/mirall/version.h.in | 1 - 25 files changed, 900 insertions(+), 327 deletions(-) create mode 100644 src/mirall/cocoainitializer.h create mode 100644 src/mirall/cocoainitializer_mac.mm create mode 100644 src/mirall/genericupdater.cpp create mode 100644 src/mirall/genericupdater.h create mode 100644 src/mirall/sparkleupdater.h create mode 100644 src/mirall/sparkleupdater_mac.mm delete mode 100644 src/mirall/updatedetector.cpp delete mode 100644 src/mirall/updatedetector.h rename src/mirall/{occinfo.cpp => updateinfo.cpp} (64%) rename src/mirall/{occinfo.h => updateinfo.h} (53%) create mode 100644 src/mirall/updater.cpp create mode 100644 src/mirall/updater.h diff --git a/VERSION.cmake b/VERSION.cmake index 15864fe21..03e923f79 100644 --- a/VERSION.cmake +++ b/VERSION.cmake @@ -10,7 +10,6 @@ endif( NOT DEFINED MIRALL_VERSION_SUFFIX ) if( NOT DEFINED MIRALL_VERSION_BUILD ) set( MIRALL_VERSION_BUILD "0" ) # Integer ID. Generated by the build system endif( NOT DEFINED MIRALL_VERSION_BUILD ) - # Composite defines # Used e.g. for libraries Keep at x.y.z. set( MIRALL_VERSION "${MIRALL_VERSION_MAJOR}.${MIRALL_VERSION_MINOR}.${MIRALL_VERSION_PATCH}" ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e17b35bd5..ccded080b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,3 @@ -#add_subdirectory(integration) - include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) qt_add_resources(MIRALL_RC_SRC ../mirall.qrc) @@ -13,6 +11,20 @@ endif() set(synclib_NAME ${APPLICATION_EXECUTABLE}sync) +if ( APPLE ) + list(APPEND OS_SPECIFIC_LINK_LIBRARIES + /System/Library/Frameworks/CoreServices.framework + /System/Library/Frameworks/Foundation.framework + /System/Library/Frameworks/AppKit.framework + ) +endif() + + +if( ENABLE_SPARKLE AND SPARKLE ) + set( HAVE_SPARKLE ON ) + list (APPEND OS_SPECIFIC_LINK_LIBRARIES ${SPARKLE}) +endif( ENABLE_SPARKLE AND SPARKLE ) + set(3rdparty_SRC 3rdparty/qtsingleapplication/qtsingleapplication.cpp 3rdparty/qtsingleapplication/qtlocalpeer.cpp @@ -121,10 +133,9 @@ IF( WIN32 ) set(libsync_HEADERS ${libsync_HEADERS} mirall/folderwatcher_win.h) ENDIF() IF( APPLE ) - set(libsync_SRCS ${libsync_SRCS} mirall/folderwatcher_mac.cpp) + list(APPEND libsync_SRCS mirall/folderwatcher_mac.cpp) ENDIF() - qt_wrap_cpp(syncMoc ${libsync_HEADERS}) # These headers are installed for libowncloudsync to be used by 3rd party apps @@ -164,11 +175,17 @@ ELSE() FIND_LIBRARY(HTTPBF_LIBRARY NAMES httpbf HINTS $ENV{CSYNC_DIR}) ENDIF() +IF( DEFINED CSYNC_BUILD_PATH ) +SET(HTTPBF_LIBRARY ${CSYNC_BUILD_PATH}/src/httpbf/libhttpbf.a) +ELSE() +FIND_LIBRARY(HTTPBF_LIBRARY NAMES httpbflib HINTS $ENV{CSYNC_DIR}) +ENDIF() list(APPEND libsync_LINK_TARGETS ${QT_LIBRARIES} ${CSYNC_LIBRARY} ${HTTPBF_LIBRARY} + ${OS_SPECIFIC_LINK_LIBRARIES} ) if(QTKEYCHAIN_FOUND) @@ -197,10 +214,6 @@ set_target_properties( ${synclib_NAME} PROPERTIES target_link_libraries(${synclib_NAME} ${libsync_LINK_TARGETS} ) -if ( APPLE ) - target_link_libraries(${synclib_NAME} /System/Library/Frameworks/CoreServices.framework) -endif() - if(NOT BUILD_OWNCLOUD_OSX_BUNDLE) install(TARGETS ${synclib_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} @@ -248,8 +261,7 @@ set(mirall_SRCS wizard/owncloudshibbolethcredspage.cpp wizard/owncloudadvancedsetuppage.cpp mirall/owncloudsetupwizard.cpp - mirall/updatedetector.cpp - mirall/occinfo.cpp + mirall/updateinfo.cpp mirall/sslerrordialog.cpp mirall/logbrowser.cpp mirall/settingsdialog.cpp @@ -259,6 +271,8 @@ set(mirall_SRCS mirall/ignorelisteditor.cpp mirall/owncloudgui.cpp mirall/socketapi.cpp + mirall/updater.cpp + mirall/genericupdater.cpp ) set(mirall_HEADERS @@ -274,7 +288,6 @@ set(mirall_HEADERS wizard/owncloudshibbolethcredspage.h wizard/owncloudadvancedsetuppage.h mirall/folderstatusmodel.h - mirall/updatedetector.h mirall/sslerrordialog.h mirall/logbrowser.h mirall/settingsdialog.h @@ -285,8 +298,19 @@ set(mirall_HEADERS mirall/protocolwidget.h mirall/owncloudgui.h mirall/socketapi.h + mirall/updater.h + mirall/genericupdater.h ) +IF( APPLE ) + list(APPEND mirall_SRCS + mirall/cocoainitializer_mac.mm + mirall/sparkleupdater_mac.mm) + list(APPEND mirall_HEADERS + mirall/cocoainitializer.h + mirall/sparkleupdater.h) +ENDIF() + # csync is required. include_directories(${CSYNC_INCLUDE_DIR}/csync ${CSYNC_INCLUDE_DIR} ${CSYNC_INCLUDE_DIR}/httpbf/src ${CSYNC_BUILD_PATH}/src) include_directories(${3rdparty_INC}) @@ -350,6 +374,9 @@ else() set(BIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}") include(DeployQt4) + option(ENABLE_SPARKLE "Sparkle updating" ON) + find_library(SPARKLE Sparkle) + set(CMAKE_INSTALL_PREFIX ".") # Examples use /Applications. hurmpf. set(MACOSX_BUNDLE_ICON_FILE "ownCloud.icns") @@ -372,6 +399,7 @@ set_target_properties( ${APPLICATION_EXECUTABLE} PROPERTIES target_link_libraries( ${APPLICATION_EXECUTABLE} ${QT_LIBRARIES} ) target_link_libraries( ${APPLICATION_EXECUTABLE} ${synclib_NAME} ) target_link_libraries( ${APPLICATION_EXECUTABLE} ${CSYNC_LIBRARY} ) +target_link_libraries( ${APPLICATION_EXECUTABLE} ${OS_SPECIFIC_LINK_LIBRARIES} ) install(TARGETS ${APPLICATION_EXECUTABLE} RUNTIME DESTINATION bin diff --git a/src/main.cpp b/src/main.cpp index 043f800dc..d91597ce9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,9 +16,13 @@ #include "mirall/application.h" #include "mirall/theme.h" #include "mirall/utility.h" +#include "mirall/cocoainitializer.h" +#include "mirall/updater.h" -#include #include +#include + +using namespace Mirall; void warnSystray() { @@ -27,13 +31,16 @@ void warnSystray() "If you are running XFCE, please follow " "these instructions. " "Otherwise, please install a system tray application such as 'trayer' and try again.") - .arg(Mirall::Theme::instance()->appNameGUI())); + .arg(Theme::instance()->appNameGUI())); } int main(int argc, char **argv) { Q_INIT_RESOURCE(mirall); +#ifdef Q_OS_MAC + Mac::CocoaInitializer cocoaInit; // RIIA +#endif Mirall::Application app(argc, argv); #ifndef Q_OS_WIN signal(SIGPIPE, SIG_IGN); @@ -43,6 +50,19 @@ int main(int argc, char **argv) return 0; } + Updater *updater = Updater::instance(); + switch (updater->updateState()) { + case Updater::UpdateAvailable: + updater->performUpdate(); + return true; + case Updater::UpdateFailed: + updater->showFallbackMessage(); + break; + case Updater::NoUpdate: + default: + break; + } + // if the application is already running, notify it. if( app.isRunning() ) { QStringList args = app.arguments(); @@ -56,7 +76,7 @@ int main(int argc, char **argv) int attempts = 0; forever { if (!QSystemTrayIcon::isSystemTrayAvailable() && qgetenv("DESKTOP_SESSION") != "ubuntu") { - Mirall::Utility::sleep(1); + Utility::sleep(1); attempts++; if (attempts < 30) continue; } else { diff --git a/src/mirall/application.cpp b/src/mirall/application.cpp index d529a2db5..9d8faa45b 100644 --- a/src/mirall/application.cpp +++ b/src/mirall/application.cpp @@ -18,19 +18,19 @@ #include "config.h" + +#include "mirall/account.h" #include "mirall/application.h" +#include "mirall/connectionvalidator.h" #include "mirall/folder.h" #include "mirall/folderman.h" -#include "mirall/folder.h" +#include "mirall/logger.h" +#include "mirall/mirallconfigfile.h" +#include "mirall/socketapi.h" #include "mirall/sslerrordialog.h" #include "mirall/theme.h" -#include "mirall/mirallconfigfile.h" -#include "mirall/updatedetector.h" -#include "mirall/logger.h" +#include "mirall/updater.h" #include "mirall/utility.h" -#include "mirall/connectionvalidator.h" -#include "mirall/socketapi.h" -#include "mirall/account.h" #include "creds/abstractcredentials.h" @@ -139,7 +139,7 @@ Application::Application(int &argc, char **argv) : // startup procedure. QTimer::singleShot( 0, this, SLOT( slotCheckConnection() )); - if( !cfg.ownCloudSkipUpdateCheck() ) { + if( !cfg.skipUpdateCheck() ) { QTimer::singleShot( 3000, this, SLOT( slotStartUpdateDetector() )); } @@ -202,8 +202,8 @@ void Application::slotCleanup() void Application::slotStartUpdateDetector() { - UpdateDetector *updateDetector = new UpdateDetector(this); - updateDetector->versionCheck(_theme); + Updater *updater = Updater::instance(); + updater->backgroundCheckForUpdate(); } void Application::slotCheckConnection() diff --git a/src/mirall/cocoainitializer.h b/src/mirall/cocoainitializer.h new file mode 100644 index 000000000..fd4200a98 --- /dev/null +++ b/src/mirall/cocoainitializer.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) by Daniel Molkentin + * + * This program 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; version 2 of the License. + * + * This program 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. + */ + +namespace Mirall { +namespace Mac { + +/** CocoaInitializer provides an AutoRelease Pool via RIIA for use in main() */ +class CocoaInitializer { +public: + CocoaInitializer(); + ~CocoaInitializer(); +private: + class Private; + Private *d; +}; + +} // namespace Mac +} // namespace Mirall diff --git a/src/mirall/cocoainitializer_mac.mm b/src/mirall/cocoainitializer_mac.mm new file mode 100644 index 000000000..b65804bda --- /dev/null +++ b/src/mirall/cocoainitializer_mac.mm @@ -0,0 +1,39 @@ +/* + * Copyright (C) by Daniel Molkentin + * + * This program 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; version 2 of the License. + * + * This program 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. + */ + +#include "mirall/cocoainitializer.h" + +#import +#import + +namespace Mirall { +namespace Mac { + +class CocoaInitializer::Private { + public: + NSAutoreleasePool* autoReleasePool; +}; + +CocoaInitializer::CocoaInitializer() { + d = new CocoaInitializer::Private(); + NSApplicationLoad(); + d->autoReleasePool = [[NSAutoreleasePool alloc] init]; +} + +CocoaInitializer::~CocoaInitializer() { + [d->autoReleasePool release]; + delete d; +} + +} // namespace Mac +} // namespace Mirall diff --git a/src/mirall/generalsettings.cpp b/src/mirall/generalsettings.cpp index 83d43864d..83d9849f9 100644 --- a/src/mirall/generalsettings.cpp +++ b/src/mirall/generalsettings.cpp @@ -19,6 +19,8 @@ #include "mirall/application.h" #include "mirall/utility.h" #include "mirall/mirallconfigfile.h" +#include "mirall/updater.h" +#include "mirall/genericupdater.h" #include #include @@ -47,6 +49,7 @@ GeneralSettings::GeneralSettings(QWidget *parent) : } loadMiscSettings(); + slotUpdateInfo(); // misc connect(_ui->monoIconsCheckBox, SIGNAL(toggled(bool)), SLOT(saveMiscSettings())); @@ -56,7 +59,6 @@ GeneralSettings::GeneralSettings(QWidget *parent) : QString themeDir = QString::fromLatin1(":/mirall/theme/%1/") .arg(Theme::instance()->systrayIconFlavor(true)); _ui->monoIconsCheckBox->setVisible(QDir(themeDir).exists()); - } GeneralSettings::~GeneralSettings() @@ -71,6 +73,20 @@ void GeneralSettings::loadMiscSettings() _ui->desktopNotificationsCheckBox->setChecked(cfgFile.optionalDesktopNotifications()); } +void GeneralSettings::slotUpdateInfo() +{ + if (GenericUpdater *updater = dynamic_cast(Updater::instance())) + { + connect(updater, SIGNAL(stateChanged()), SLOT(slotUpdateInfo()), Qt::UniqueConnection); + connect(_ui->restartButton, SIGNAL(clicked()), updater, SLOT(slotStartInstaller()), Qt::UniqueConnection); + _ui->updateStateLabel->setText(updater->statusString()); + _ui->restartButton->setVisible(updater->state() == GenericUpdater::UpdateAvailable); + } else { + // can't have those infos from sparkle currently + _ui->updatesGroupBox->setVisible(false); + } +} + void GeneralSettings::saveMiscSettings() { MirallConfigFile cfgFile; diff --git a/src/mirall/generalsettings.h b/src/mirall/generalsettings.h index f0c9ca671..16487de8e 100644 --- a/src/mirall/generalsettings.h +++ b/src/mirall/generalsettings.h @@ -38,6 +38,7 @@ private slots: void saveMiscSettings(); void slotToggleLaunchOnStartup(bool); void slotToggleOptionalDesktopNotifications(bool); + void slotUpdateInfo(); private: void loadMiscSettings(); diff --git a/src/mirall/generalsettings.ui b/src/mirall/generalsettings.ui index a9d5ed502..7c9736852 100644 --- a/src/mirall/generalsettings.ui +++ b/src/mirall/generalsettings.ui @@ -7,7 +7,7 @@ 0 0 468 - 169 + 249 @@ -60,6 +60,54 @@ + + + + Updates + + + + + + + + + true + + + + + + + + 0 + 0 + + + + &Restart && Update + + + + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 40 + 20 + + + + + + + diff --git a/src/mirall/genericupdater.cpp b/src/mirall/genericupdater.cpp new file mode 100644 index 000000000..6e0052185 --- /dev/null +++ b/src/mirall/genericupdater.cpp @@ -0,0 +1,355 @@ +/* + * Copyright (C) by Klaas Freitag + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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. + */ + +#include "mirall/genericupdater.h" +#include "mirall/theme.h" +#include "mirall/version.h" +#include "mirall/mirallconfigfile.h" +#include "mirall/utility.h" +#include "mirall/mirallaccessmanager.h" + +#include +#include +#include +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) +#include +#endif + +#include + +namespace Mirall { + +static const char updateAvailableC[] = "Updater/updateAvailable"; +static const char lastVersionC[] = "Updater/lastVersion"; +static const char ranUpdateC[] = "Updater/ranUpdate"; + +GenericUpdater::GenericUpdater(const QUrl &url, QObject *parent) : + QObject(parent) + , _updateUrl(url) + , _accessManager(new MirallAccessManager(this)) + , _state(Unknown) + , _showFallbackMessage(false) +{ +} + +Updater::UpdateState GenericUpdater::updateState() const +{ + MirallConfigFile cfg; + QSettings settings(cfg.configFile(), QSettings::IniFormat); + QString updateFile = settings.value(updateAvailableC).toString(); + bool exists = QFile(updateFile).exists(); + if (!updateFile.isEmpty() && exists) { + // we have an update, did we succeed running it? + bool ranUpdate = settings.value(ranUpdateC, false).toBool(); + if (ranUpdate) { + if (updateSucceeded()) { + settings.remove(ranUpdateC); + return NoUpdate; + } else { + return UpdateFailed; + } + } else { + return UpdateAvailable; + } + } else { + return NoUpdate; + } +} + +void GenericUpdater::performUpdate() +{ + MirallConfigFile cfg; + QSettings settings(cfg.configFile(), QSettings::IniFormat); + QString updateFile = settings.value(updateAvailableC).toString(); + if (!updateFile.isEmpty() && QFile(updateFile).exists()) { + if (QMessageBox::information(0, tr("New Update Ready"), + tr("A new update is about to be installed. The updater may ask\n" + "for additional privileges during the process."), QMessageBox::Ok)) { + slotStartInstaller(); + } + } +} + +void GenericUpdater::backgroundCheckForUpdate() +{ + // FIXME + checkForUpdate(); +} + +void GenericUpdater::showFallbackMessage() +{ + _showFallbackMessage = true; +} + +QString GenericUpdater::statusString() const +{ + QString updateVersion = _updateInfo.version(); + + switch (state()) { + case DownloadingUpdate: + return tr("Downloading version %1. Please wait...").arg(updateVersion); + case DownloadedUpdate: + return tr("Version %1 available. Restart application to start the update.").arg(updateVersion); + case DownloadFailed: + return tr("Could not download update. Please click here %2 to download the update manually").arg(_updateInfo.web(), updateVersion); + case UpdateButNoDownloadAvailable: + return tr("New version %1 available. Please use the systems update tool to install it.").arg(updateVersion); + case Unknown: + return tr("Checking update server..."); + case UpToDate: + // fall through + default: + return tr("Your installation is at the latest version"); + } +} + +int GenericUpdater::state() const +{ + return _state; +} + +void GenericUpdater::setState(int state) +{ + _state = state; + emit stateChanged(); +} + +void GenericUpdater::slotStartInstaller() +{ + MirallConfigFile cfg; + QSettings settings(cfg.configFile(), QSettings::IniFormat); + QString updateFile = settings.value(updateAvailableC).toString(); + settings.setValue(ranUpdateC, true); + qDebug() << "Running updater" << updateFile; + QProcess::startDetached(updateFile, QStringList() << "/S"); + qApp->quit(); +} + +void GenericUpdater::checkForUpdate() +{ + Theme *theme = Theme::instance(); + QUrl url(_updateUrl); + QString platform = QLatin1String("stranger"); + if (Utility::isLinux()) { + platform = QLatin1String("linux"); + } else if (Utility::isWindows()) { + platform = QLatin1String("win32"); + } else if (Utility::isMac()) { + platform = QLatin1String("macos"); + } + qDebug() << "00 client update check to " << url.toString(); + + QString sysInfo = getSystemInfo(); + if( !sysInfo.isEmpty() ) { + url.addQueryItem(QLatin1String("client"), sysInfo ); + } + url.addQueryItem( QLatin1String("version"), clientVersion() ); + url.addQueryItem( QLatin1String("platform"), platform ); + url.addQueryItem( QLatin1String("oem"), theme->appName() ); + + QNetworkReply *reply = _accessManager->get( QNetworkRequest(url) ); + connect(reply, SIGNAL(finished()), this, + SLOT(slotVersionInfoArrived()) ); + +} + +void GenericUpdater::slotOpenUpdateUrl() +{ + QDesktopServices::openUrl(_updateInfo.web()); +} + +void GenericUpdater::slotSetVersionSeen() +{ + MirallConfigFile cfg; + cfg.setSeenVersion(_updateInfo.version()); +} + +QString GenericUpdater::getSystemInfo() +{ +#ifdef Q_OS_LINUX + QProcess process; + process.start( QLatin1String("lsb_release -a") ); + process.waitForFinished(); + QByteArray output = process.readAllStandardOutput(); + qDebug() << "Sys Info size: " << output.length(); + if( output.length() > 1024 ) output.clear(); // don't send too much. + + return QString::fromLocal8Bit( output.toBase64() ); +#else + return QString::null; +#endif +} + +void GenericUpdater::showDialog() +{ + // if the version tag is set, there is a newer version. + QDialog *msgBox = new QDialog; + msgBox->setAttribute(Qt::WA_DeleteOnClose); + + QIcon info = msgBox->style()->standardIcon(QStyle::SP_MessageBoxInformation, 0, 0); + int iconSize = msgBox->style()->pixelMetric(QStyle::PM_MessageBoxIconSize, 0, 0); + + msgBox->setWindowIcon(info); + + QVBoxLayout *layout = new QVBoxLayout(msgBox); + QHBoxLayout *hlayout = new QHBoxLayout; + layout->addLayout(hlayout); + + msgBox->setWindowTitle(tr("New Version Available")); + + QLabel *ico = new QLabel; + ico->setFixedSize(iconSize, iconSize); + ico->setPixmap(info.pixmap(iconSize)); + QLabel *lbl = new QLabel; + QString txt = tr("

A new version of the %1 Client is available.

" + "

%2 is available for download. The installed version is %3.

") + .arg(Theme::instance()->appNameGUI()).arg(_updateInfo.versionString()).arg(clientVersion()); + + lbl->setText(txt); + lbl->setTextFormat(Qt::RichText); + lbl->setWordWrap(true); + + hlayout->addWidget(ico); + hlayout->addWidget(lbl); + + QDialogButtonBox *bb = new QDialogButtonBox; + bb->setWindowFlags(bb->windowFlags() & ~Qt::WindowContextHelpButtonHint); + QPushButton *skip = bb->addButton(tr("Skip this version"), QDialogButtonBox::ResetRole); + QPushButton *reject = bb->addButton(tr("Skip this time"), QDialogButtonBox::AcceptRole); + QPushButton *getupdate = bb->addButton(tr("Get update"), QDialogButtonBox::AcceptRole); + + connect(skip, SIGNAL(clicked()), msgBox, SLOT(reject())); + connect(reject, SIGNAL(clicked()), msgBox, SLOT(reject())); + connect(getupdate, SIGNAL(clicked()), msgBox, SLOT(accept())); + + connect(skip, SIGNAL(clicked()), SLOT(slotSetVersionSeen())); + connect(getupdate, SIGNAL(clicked()), SLOT(slotOpenUpdateUrl())); + + layout->addWidget(bb); + + msgBox->open(); +} + +void GenericUpdater::slotVersionInfoArrived() +{ + QNetworkReply *reply = qobject_cast(sender()); + if( reply->error() != QNetworkReply::NoError ) { + qDebug() << "Failed to reach version check url: " << reply->errorString(); + return; + } + + QString xml = QString::fromUtf8(reply->readAll()); + + bool ok; + _updateInfo = UpdateInfo::parseString( xml, &ok ); + if( ok ) { + + // Thats how it looks like if a new version is available: + // + // + // 1.0.0 + // ownCloud Client 1.0.0 + // http://ownCloud.org/client/update + // + // + // and thats if no new version available: + // + // + // + // + // + // + MirallConfigFile cfg; + if( _updateInfo.version().isEmpty() || _updateInfo.version() == cfg.seenVersion() ) { + qDebug() << "Client is on latest version!"; + setState(UpToDate); + } else { + QString url = _updateInfo.downloadUrl(); + if (url.isEmpty() || _showFallbackMessage) { + if (Utility::isWindows()) { + showDialog(); + } + setState(UpdateButNoDownloadAvailable); + } else { + _targetFile = cfg.configPath() + url.mid(url.lastIndexOf('/')); + if (QFile(_targetFile).exists()) { + setState(DownloadedUpdate); + } else { + QNetworkReply *reply = _accessManager->get(QNetworkRequest(QUrl(url))); + connect(reply, SIGNAL(readyRead()), SLOT(slotWriteFile())); + connect(reply, SIGNAL(finished()), SLOT(slotDownloadFinished())); + setState(DownloadingUpdate); + _file.reset(new QTemporaryFile); + _file->setAutoRemove(true); + _file->open(); + } + } + } + } else { + qDebug() << "Could not parse update information."; + } +} + +void GenericUpdater::slotWriteFile() +{ + QNetworkReply *reply = qobject_cast(sender()); + if(_file->isOpen()) { + _file->write(reply->readAll()); + } +} + +void GenericUpdater::slotDownloadFinished() +{ + QNetworkReply *reply = qobject_cast(sender()); + if (reply->error() != QNetworkReply::NoError) { + setState(DownloadFailed); + return; + } + + QUrl url(reply->url()); + _file->close(); + QFile::copy(_file->fileName(), _targetFile); + setState(DownloadedUpdate); + qDebug() << "Downloaded" << url.toString() << "to" << _targetFile; + MirallConfigFile cfg; + QSettings settings(cfg.configFile(), QSettings::IniFormat); + settings.setValue(lastVersionC, clientVersion()); + settings.setValue(updateAvailableC, _targetFile); + +} + +static qint64 versionToInt(qint64 major, qint64 minor, qint64 patch, qint64 build) +{ + return major << 56 | minor << 48 | patch << 40 | build; +} + +bool GenericUpdater::updateSucceeded() const +{ + MirallConfigFile cfg; + QSettings settings(cfg.configFile(), QSettings::IniFormat); + QByteArray lastVersion = settings.value(lastVersionC).toString().toLatin1(); + int major = 0, minor = 0, patch = 0, build = 0; + sscanf(lastVersion, "%d.%d.%d.%d", &major, &minor, &patch, &build); + qint64 oldVersionInt = versionToInt(major, minor, patch, build); + qint64 versionInt = versionToInt(MIRALL_VERSION_MAJOR, MIRALL_VERSION_MINOR, + MIRALL_VERSION_PATCH, MIRALL_VERSION_BUILD); + return versionInt > oldVersionInt; +} + +QString GenericUpdater::clientVersion() const +{ + return QString::fromLatin1(MIRALL_STRINGIFY(MIRALL_VERSION_FULL)); +} + +} diff --git a/src/mirall/genericupdater.h b/src/mirall/genericupdater.h new file mode 100644 index 000000000..adc1d5120 --- /dev/null +++ b/src/mirall/genericupdater.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) by Klaas Freitag + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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. + */ + +#ifndef UPDATEDETECTOR_H +#define UPDATEDETECTOR_H + +#include +#include +#include + +#include "mirall/updateinfo.h" +#include "mirall/updater.h" + +class QNetworkAccessManager; +class QNetworkReply; + +namespace Mirall { + +class GenericUpdater : public QObject, public Updater +{ + Q_OBJECT +public: + enum DownloadState { Unknown = 0, UpToDate, DownloadingUpdate, DownloadedUpdate, + DownloadFailed, UpdateButNoDownloadAvailable }; + explicit GenericUpdater(const QUrl &url, QObject *parent = 0); + + UpdateState updateState() const; + void performUpdate(); + + void checkForUpdate(); + void backgroundCheckForUpdate(); + + void showFallbackMessage(); + + QString statusString() const; + int state() const; + void setState(int state); + +signals: + void stateChanged(); + +public slots: + void slotStartInstaller(); + +private slots: + void slotOpenUpdateUrl(); + void slotSetVersionSeen(); + void slotVersionInfoArrived(); + void slotWriteFile(); + void slotDownloadFinished(); + +private: + bool updateSucceeded() const; + QString clientVersion() const; + QString getSystemInfo(); + void showDialog(); + + QString _targetFile; + QUrl _updateUrl; + QNetworkAccessManager *_accessManager; + UpdateInfo _updateInfo; + QScopedPointer _file; + int _state; + bool _showFallbackMessage; +}; + +} + +#endif // UPDATEDETECTOR_H diff --git a/src/mirall/mirallconfigfile.cpp b/src/mirall/mirallconfigfile.cpp index d061308d8..e41feb8ad 100644 --- a/src/mirall/mirallconfigfile.cpp +++ b/src/mirall/mirallconfigfile.cpp @@ -60,7 +60,6 @@ static const char downloadLimitC[] = "BWLimit/downloadLimit"; static const char seenVersionC[] = "Updater/seenVersion"; static const char maxLogLinesC[] = "Logging/maxLogLines"; -QString MirallConfigFile::_oCVersion; QString MirallConfigFile::_confDir = QString::null; bool MirallConfigFile::_askedUser = false; @@ -334,19 +333,7 @@ quint64 MirallConfigFile::forceSyncInterval(const QString& connection) const return interval; } -QString MirallConfigFile::ownCloudVersion() const -{ - return _oCVersion; -} - -void MirallConfigFile::setOwnCloudVersion( const QString& ver) -{ - qDebug() << "** Setting ownCloud Server version to " << ver; - _oCVersion = ver; -} - - -bool MirallConfigFile::ownCloudSkipUpdateCheck( const QString& connection ) const +bool MirallConfigFile::skipUpdateCheck( const QString& connection ) const { QString con( connection ); if( connection.isEmpty() ) con = defaultConnection(); @@ -359,7 +346,7 @@ bool MirallConfigFile::ownCloudSkipUpdateCheck( const QString& connection ) cons return skipIt; } -void MirallConfigFile::setOwnCloudSkipUpdateCheck( bool skip, const QString& connection ) +void MirallConfigFile::setSkipUpdateCheck( bool skip, const QString& connection ) { QString con( connection ); if( connection.isEmpty() ) con = defaultConnection(); diff --git a/src/mirall/mirallconfigfile.h b/src/mirall/mirallconfigfile.h index 31138bdd0..54f558161 100644 --- a/src/mirall/mirallconfigfile.h +++ b/src/mirall/mirallconfigfile.h @@ -55,9 +55,6 @@ public: int maxLogLines() const; void setMaxLogLines(int); - bool ownCloudSkipUpdateCheck( const QString& connection = QString() ) const; - void setOwnCloudSkipUpdateCheck( bool, const QString& ); - /* Server poll interval in milliseconds */ int remotePollInterval( const QString& connection = QString() ) const; /* Set poll interval. Value in microseconds has to be larger than 5000 */ @@ -99,12 +96,19 @@ public: bool optionalDesktopNotifications() const; void setOptionalDesktopNotifications(bool show); - QString seenVersion() const; - void setSeenVersion(const QString &version); - void saveGeometry(QWidget *w); void restoreGeometry(QWidget *w); + // installer + bool skipUpdateCheck( const QString& connection = QString() ) const; + void setSkipUpdateCheck( bool, const QString& ); + + QString lastVersion() const; + void setLastVersion(const QString &version); + + QString seenVersion() const; + void setSeenVersion(const QString &version); + void saveGeometryHeader(QHeaderView *header); void restoreGeometryHeader(QHeaderView *header); protected: diff --git a/src/mirall/networkjobs.cpp b/src/mirall/networkjobs.cpp index 48c2d16b6..52ff4fb40 100644 --- a/src/mirall/networkjobs.cpp +++ b/src/mirall/networkjobs.cpp @@ -135,6 +135,8 @@ QNetworkReply *AbstractNetworkJob::headRequest(const QUrl &url) void AbstractNetworkJob::slotFinished() { + qDebug() << _reply->error() << _reply->errorString(); + static QMutex mutex; AbstractCredentials *creds = _account->credentials(); if (creds->stillValid(_reply) || _ignoreCredentialFailure) { diff --git a/src/mirall/sparkleupdater.h b/src/mirall/sparkleupdater.h new file mode 100644 index 000000000..26d1ae3f4 --- /dev/null +++ b/src/mirall/sparkleupdater.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) by Daniel Molkentin + * + * This program 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; version 2 of the License. + * + * This program 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. + */ + +#ifndef SPARKLEUPDATER_H +#define SPARKLEUPDATER_H + +#include "mirall/updater.h" + +#include + +namespace Mirall { + +class SparkleUpdater : public Updater { +public: + SparkleUpdater(const QString& appCastUrl, QObject *parent = 0); + ~SparkleUpdater(); + + void checkForUpdate(); + void backgroundCheckForUpdate(); +private: + class Private; + Private *d; +}; + +} // namespace Mirall + +#endif // SPARKLEUPDATER_H diff --git a/src/mirall/sparkleupdater_mac.mm b/src/mirall/sparkleupdater_mac.mm new file mode 100644 index 000000000..676745196 --- /dev/null +++ b/src/mirall/sparkleupdater_mac.mm @@ -0,0 +1,63 @@ +/* + * Copyright (C) by Daniel Molkentin + * + * This program 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; version 2 of the License. + * + * This program 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. + */ + + +#include +#include +#include + +#include "mirall/sparkleupdater.h" +#include "mirall/utility.h" + +namespace Mirall { + +class SparkleUpdater::Private +{ + public: + SUUpdater* updater; +}; + +SparkleUpdater::SparkleUpdater(const QString& appCastUrl, QObject *parent) + : Updater(parent) +{ + d = new Private; + + d->updater = [SUUpdater sharedUpdater]; + [d->updater retain]; + + NSURL* url = [NSURL URLWithString: + [NSString stringWithUTF8String: appCastUrl.toUtf8().data()]]; + [d->updater setFeedURL: url]; + +// requires a more recent version +// NSString *userAgent = [NSString stringWithUTF8String: Utility::userAgentString().data()]; +// [d->updater setUserAgentString: userAgent]; +} + +SparkleUpdater::~SparkleUpdater() +{ + [d->updater release]; + delete d; +} + +void SparkleUpdater::checkForUpdates() +{ + [d->updater checkForUpdates: NSApp]; +} + +void SparkleUpdater::backgroundCheckForUpdates() +{ + [d->updater checkForUpdatesInBackground]; +} + +} // namespace Mirall diff --git a/src/mirall/updatedetector.cpp b/src/mirall/updatedetector.cpp deleted file mode 100644 index 34192333e..000000000 --- a/src/mirall/updatedetector.cpp +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (C) by Klaas Freitag - * - * This program 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 2 of the License, or - * (at your option) any later version. - * - * This program 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. - */ - -#include "mirall/updatedetector.h" -#include "mirall/theme.h" -#include "mirall/version.h" -#include "mirall/mirallconfigfile.h" -#include "mirall/occinfo.h" -#include "mirall/utility.h" -#include "mirall/mirallaccessmanager.h" - -#include -#include -#include -#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) -#include -#endif - - -namespace Mirall { - - -UpdateDetector::UpdateDetector(QObject *parent) : - QObject(parent) - , _accessManager(new MirallAccessManager(this)) -{ -} - -void UpdateDetector::versionCheck( Theme *theme ) -{ - connect(_accessManager, SIGNAL(finished(QNetworkReply*)), this, - SLOT(slotVersionInfoArrived(QNetworkReply*)) ); - QUrl url(Theme::instance()->updateCheckUrl()); - - QString platform = QLatin1String("stranger"); -#ifdef Q_OS_LINUX - platform = QLatin1String("linux"); -#endif -#ifdef Q_OS_WIN - platform = QLatin1String( "win32" ); -#endif -#ifdef Q_OS_MAC - platform = QLatin1String( "macos" ); -#endif - qDebug() << "00 client update check to " << url.toString(); - - QString sysInfo = getSystemInfo(); - if( !sysInfo.isEmpty() ) { - url.addQueryItem(QLatin1String("client"), sysInfo ); - } - url.addQueryItem( QLatin1String("version"), - QLatin1String(MIRALL_STRINGIFY(MIRALL_VERSION_FULL)) ); - url.addQueryItem( QLatin1String("platform"), platform ); - url.addQueryItem( QLatin1String("oem"), theme->appName() ); - - QNetworkRequest req( url ); - req.setRawHeader( QByteArray("User-Agent"), Utility::userAgentString() ); - - _accessManager->get( req ); -} - -void UpdateDetector::slotOpenUpdateUrl() -{ - QDesktopServices::openUrl(ocClient.web()); -} - -void UpdateDetector::slotSetVersionSeen() -{ - MirallConfigFile cfg; - cfg.setSeenVersion(ocClient.version()); -} - -QString UpdateDetector::getSystemInfo() -{ -#ifdef Q_OS_LINUX - QProcess process; - process.start( QLatin1String("lsb_release -a") ); - process.waitForFinished(); - QByteArray output = process.readAllStandardOutput(); - qDebug() << "Sys Info size: " << output.length(); - if( output.length() > 1024 ) output.clear(); // don't send too much. - - return QString::fromLocal8Bit( output.toBase64() ); -#else - return QString::null; -#endif -} - -void UpdateDetector::showDialog() -{ - QDialog *msgBox = new QDialog; - - QIcon info = msgBox->style()->standardIcon(QStyle::SP_MessageBoxInformation, 0, 0); - int iconSize = msgBox->style()->pixelMetric(QStyle::PM_MessageBoxIconSize, 0, 0); - - msgBox->setWindowIcon(info); - - QVBoxLayout *layout = new QVBoxLayout(msgBox); - QHBoxLayout *hlayout = new QHBoxLayout; - layout->addLayout(hlayout); - - msgBox->setWindowTitle(tr("New Version Available")); - - QLabel *ico = new QLabel; - ico->setFixedSize(iconSize, iconSize); - ico->setPixmap(info.pixmap(iconSize)); - QLabel *lbl = new QLabel; - QString txt = tr("

A new version of the %1 Client is available.

" - "

%2 is available for download. The installed version is %3.

") - .arg(Theme::instance()->appNameGUI()).arg(ocClient.versionstring()) - .arg(QLatin1String(MIRALL_STRINGIFY(MIRALL_VERSION_FULL))); - - lbl->setText(txt); - lbl->setTextFormat(Qt::RichText); - lbl->setWordWrap(true); - - hlayout->addWidget(ico); - hlayout->addWidget(lbl); - - QDialogButtonBox *bb = new QDialogButtonBox; - bb->setWindowFlags(bb->windowFlags() & ~Qt::WindowContextHelpButtonHint); - QPushButton *skip = bb->addButton(tr("Skip update"), QDialogButtonBox::ResetRole); - QPushButton *reject = bb->addButton(tr("Skip this time"), QDialogButtonBox::AcceptRole); - QPushButton *getupdate = bb->addButton(tr("Get update"), QDialogButtonBox::AcceptRole); - - connect(skip, SIGNAL(clicked()), msgBox, SLOT(reject())); - connect(reject, SIGNAL(clicked()), msgBox, SLOT(reject())); - connect(getupdate, SIGNAL(clicked()), msgBox, SLOT(accept())); - - connect(skip, SIGNAL(clicked()), SLOT(slotSetVersionSeen())); - connect(getupdate, SIGNAL(clicked()), SLOT(slotOpenUpdateUrl())); - - layout->addWidget(bb); - - msgBox->open(); - msgBox->resize(400, msgBox->sizeHint().height()); -} - -void UpdateDetector::slotVersionInfoArrived( QNetworkReply* reply ) -{ - if( reply->error() != QNetworkReply::NoError ) { - qDebug() << "Failed to reach version check url: " << reply->errorString(); - return; - } - - QString xml = QString::fromUtf8(reply->readAll()); - - bool ok; - ocClient = Owncloudclient::parseString( xml, &ok ); - if( ok ) { - - // Thats how it looks like if a new version is available: - // - // - // 1.0.0 - // ownCloud Client 1.0.0 - // http://ownCloud.org/client/update - // - // - // and thats if no new version available: - // - // - // - // - // - // - MirallConfigFile cfg; - if( ocClient.version().isEmpty() || ocClient.version() == cfg.seenVersion() ) { - qDebug() << "Client is on latest version!"; - } else { - showDialog(); - } - } else { - qDebug() << "Could not parse update information."; - } -} - -} diff --git a/src/mirall/updatedetector.h b/src/mirall/updatedetector.h deleted file mode 100644 index 680144524..000000000 --- a/src/mirall/updatedetector.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) by Klaas Freitag - * - * This program 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 2 of the License, or - * (at your option) any later version. - * - * This program 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. - */ - -#ifndef UPDATEDETECTOR_H -#define UPDATEDETECTOR_H - -#include - -#include "mirall/occinfo.h" - -class QNetworkAccessManager; -class QNetworkReply; - -namespace Mirall { - -class Theme; - -class UpdateDetector : public QObject -{ - Q_OBJECT -public: - explicit UpdateDetector(QObject *parent = 0); - - void versionCheck( Theme * ); -signals: - -public slots: - -private slots: - void slotOpenUpdateUrl(); - void slotSetVersionSeen(); - void slotVersionInfoArrived( QNetworkReply* ); - -private: - QString getSystemInfo(); - void showDialog(); - - QNetworkAccessManager *_accessManager; - Owncloudclient ocClient; -}; - -} - -#endif // UPDATEDETECTOR_H diff --git a/src/mirall/occinfo.cpp b/src/mirall/updateinfo.cpp similarity index 64% rename from src/mirall/occinfo.cpp rename to src/mirall/updateinfo.cpp index d419c7bae..7554a0d11 100644 --- a/src/mirall/occinfo.cpp +++ b/src/mirall/updateinfo.cpp @@ -1,7 +1,7 @@ // This file is generated by kxml_compiler from occinfo.xml. // All changes you do to this file will be lost. -#include "occinfo.h" +#include "updateinfo.h" #include #include @@ -11,45 +11,55 @@ namespace Mirall { -void Owncloudclient::setVersion( const QString &v ) +void UpdateInfo::setVersion( const QString &v ) { mVersion = v; } -QString Owncloudclient::version() const +QString UpdateInfo::version() const { return mVersion; } -void Owncloudclient::setVersionstring( const QString &v ) +void UpdateInfo::setVersionString( const QString &v ) { - mVersionstring = v; + mVersionString = v; } -QString Owncloudclient::versionstring() const +QString UpdateInfo::versionString() const { - return mVersionstring; + return mVersionString; } -void Owncloudclient::setWeb( const QString &v ) +void UpdateInfo::setWeb( const QString &v ) { mWeb = v; } -QString Owncloudclient::web() const +QString UpdateInfo::web() const { return mWeb; } -Owncloudclient Owncloudclient::parseElement( const QDomElement &element, bool *ok ) +void UpdateInfo::setDownloadUrl( const QString &v ) +{ + mDownloadUrl = v; +} + +QString UpdateInfo::downloadUrl() const +{ + return mDownloadUrl; +} + +UpdateInfo UpdateInfo::parseElement( const QDomElement &element, bool *ok ) { if ( element.tagName() != QLatin1String("owncloudclient") ) { qCritical() << "Expected 'owncloudclient', got '" << element.tagName() << "'."; if ( ok ) *ok = false; - return Owncloudclient(); + return UpdateInfo(); } - Owncloudclient result = Owncloudclient(); + UpdateInfo result = UpdateInfo(); QDomNode n; for( n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) { @@ -58,11 +68,14 @@ Owncloudclient Owncloudclient::parseElement( const QDomElement &element, bool *o result.setVersion( e.text() ); } else if ( e.tagName() == QLatin1String("versionstring") ) { - result.setVersionstring( e.text() ); + result.setVersionString( e.text() ); } else if ( e.tagName() == QLatin1String("web") ) { result.setWeb( e.text() ); } + else if ( e.tagName() == QLatin1String("downloadurl") ) { + result.setDownloadUrl( e.text() ); + } } @@ -70,28 +83,31 @@ Owncloudclient Owncloudclient::parseElement( const QDomElement &element, bool *o return result; } -void Owncloudclient::writeElement( QXmlStreamWriter &xml ) +void UpdateInfo::writeElement( QXmlStreamWriter &xml ) { xml.writeStartElement( QLatin1String("owncloudclient") ); if ( !version().isEmpty() ) { xml.writeTextElement( QLatin1String("version"), version() ); } - if ( !versionstring().isEmpty() ) { - xml.writeTextElement( QLatin1String("versionstring"), versionstring() ); + if ( !versionString().isEmpty() ) { + xml.writeTextElement( QLatin1String("versionstring"), versionString() ); } if ( !web().isEmpty() ) { xml.writeTextElement( QLatin1String("web"), web() ); } + if ( !downloadUrl().isEmpty() ) { + xml.writeTextElement( QLatin1String("downloadurl"), web() ); + } xml.writeEndElement(); } -Owncloudclient Owncloudclient::parseFile( const QString &filename, bool *ok ) +UpdateInfo UpdateInfo::parseFile( const QString &filename, bool *ok ) { QFile file( filename ); if ( !file.open( QIODevice::ReadOnly ) ) { qCritical() << "Unable to open file '" << filename << "'"; if ( ok ) *ok = false; - return Owncloudclient(); + return UpdateInfo(); } QString errorMsg; @@ -100,18 +116,18 @@ Owncloudclient Owncloudclient::parseFile( const QString &filename, bool *ok ) if ( !doc.setContent( &file, false, &errorMsg, &errorLine, &errorCol ) ) { qCritical() << errorMsg << " at " << errorLine << "," << errorCol; if ( ok ) *ok = false; - return Owncloudclient(); + return UpdateInfo(); } bool documentOk; - Owncloudclient c = parseElement( doc.documentElement(), &documentOk ); + UpdateInfo c = parseElement( doc.documentElement(), &documentOk ); if ( ok ) { *ok = documentOk; } return c; } -Owncloudclient Owncloudclient::parseString( const QString &xml, bool *ok ) +UpdateInfo UpdateInfo::parseString( const QString &xml, bool *ok ) { QString errorMsg; int errorLine, errorCol; @@ -119,18 +135,18 @@ Owncloudclient Owncloudclient::parseString( const QString &xml, bool *ok ) if ( !doc.setContent( xml, false, &errorMsg, &errorLine, &errorCol ) ) { qCritical() << errorMsg << " at " << errorLine << "," << errorCol; if ( ok ) *ok = false; - return Owncloudclient(); + return UpdateInfo(); } bool documentOk; - Owncloudclient c = parseElement( doc.documentElement(), &documentOk ); + UpdateInfo c = parseElement( doc.documentElement(), &documentOk ); if ( ok ) { *ok = documentOk; } return c; } -bool Owncloudclient::writeFile( const QString &filename ) +bool UpdateInfo::writeFile( const QString &filename ) { QFile file( filename ); if ( !file.open( QIODevice::WriteOnly ) ) { diff --git a/src/mirall/occinfo.h b/src/mirall/updateinfo.h similarity index 53% rename from src/mirall/occinfo.h rename to src/mirall/updateinfo.h index a46e5ef34..25d3e5488 100644 --- a/src/mirall/occinfo.h +++ b/src/mirall/updateinfo.h @@ -1,7 +1,7 @@ // This file is generated by kxml_compiler from occinfo.xml. // All changes you do to this file will be lost. -#ifndef OCCINFO_H -#define OCCINFO_H +#ifndef UPDATEINFO_H +#define UPDATEINFO_H #include #include @@ -9,30 +9,33 @@ namespace Mirall { -class Owncloudclient +class UpdateInfo { public: void setVersion( const QString &v ); QString version() const; - void setVersionstring( const QString &v ); - QString versionstring() const; + void setVersionString( const QString &v ); + QString versionString() const; void setWeb( const QString &v ); QString web() const; + void setDownloadUrl( const QString &v ); + QString downloadUrl() const; /** Parse XML object from DOM element. */ - static Owncloudclient parseElement( const QDomElement &element, bool *ok ); + static UpdateInfo parseElement( const QDomElement &element, bool *ok ); void writeElement( QXmlStreamWriter &xml ); - static Owncloudclient parseFile( const QString &filename, bool *ok ); - static Owncloudclient parseString( const QString &xml, bool *ok ); + static UpdateInfo parseFile( const QString &filename, bool *ok ); + static UpdateInfo parseString( const QString &xml, bool *ok ); bool writeFile( const QString &filename ); private: QString mVersion; - QString mVersionstring; + QString mVersionString; QString mWeb; + QString mDownloadUrl; }; } // namespace Mirall -#endif +#endif // UPDATEINFO_H diff --git a/src/mirall/updater.cpp b/src/mirall/updater.cpp new file mode 100644 index 000000000..628df6754 --- /dev/null +++ b/src/mirall/updater.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) by Daniel Molkentin + * + * This program 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; version 2 of the License. + * + * This program 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. + */ + +#include "mirall/updater.h" +#include "mirall/sparkleupdater.h" +#include "mirall/genericupdater.h" + +namespace Mirall { + +Updater *Updater::_instance = 0; + +Updater * Updater::instance() +{ + if(!_instance) { + _instance = create(); + } + return _instance; +} + +Updater *Updater::create() +{ +#ifdef Q_OS_MAC + return new SparkleUpdater(QLatin1String("https://updates.owncloud.com/testing/feed.rss")); +#else + // the best we can do is notify about updates + return new GenericUpdater(QUrl("https://updates.owncloud.com/testing/")); +#endif +} + +} // namespace Mirall diff --git a/src/mirall/updater.h b/src/mirall/updater.h new file mode 100644 index 000000000..61afd671e --- /dev/null +++ b/src/mirall/updater.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) by Daniel Molkentin + * + * This program 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; version 2 of the License. + * + * This program 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. + */ + +#ifndef UPDATER_H +#define UPDATER_H + +#include + +namespace Mirall { + +class Updater { +public: + enum UpdateState { NoUpdate = 0, UpdateAvailable, UpdateFailed }; + + static Updater *instance(); + + virtual void checkForUpdate() = 0; + virtual void backgroundCheckForUpdate() = 0; + + virtual UpdateState updateState() const = 0; + virtual void performUpdate() {} + + virtual void showFallbackMessage() {} + +private: + static Updater *create(); + static Updater *_instance; +}; + +} // namespace Mirall + +#endif // UPDATER_H diff --git a/src/mirall/utility.cpp b/src/mirall/utility.cpp index 53c54922b..cbd4d6a58 100644 --- a/src/mirall/utility.cpp +++ b/src/mirall/utility.cpp @@ -462,5 +462,14 @@ bool Utility::isUnix() #endif } +bool Utility::isLinux() +{ +#ifdef Q_OS_LINUX + return true; +#else + return false; +#endif +} + } // namespace Mirall diff --git a/src/mirall/utility.h b/src/mirall/utility.h index 0236a4f05..a8ce385d9 100644 --- a/src/mirall/utility.h +++ b/src/mirall/utility.h @@ -58,6 +58,7 @@ namespace Utility bool isWindows(); bool isMac(); bool isUnix(); + bool isLinux(); // use with care } } diff --git a/src/mirall/version.h.in b/src/mirall/version.h.in index d16e57932..29740f11a 100644 --- a/src/mirall/version.h.in +++ b/src/mirall/version.h.in @@ -29,5 +29,4 @@ #define MIRALL_VERSION_STRING "@MIRALL_VERSION_STRING@" - #endif // VERSION_H