diff --git a/.gitignore b/.gitignore index fae40b00..347b91b1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,10 @@ config.h +.DS_Store *.pyc +*.o *~ \.*.swp +*build-gui-Desktop_Qt* /bin /lib /build diff --git a/CMakeLists.txt b/CMakeLists.txt index fc5a3311..45c8d9d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ # Version number for Synergy set(VERSION_MAJOR 1) set(VERSION_MINOR 8) -set(VERSION_REV 4) +set(VERSION_REV 5) set(VERSION_STAGE stable) set(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REV}") diff --git a/ChangeLog b/ChangeLog index 19d10d50..477426ca 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,16 +1,22 @@ +v1.8.5-stable +============= +Bug #5680 - Server crashes when disconnecting SSL clients +Bug #5626 - Build fails using Xcode 8 and macOS SDK 10.12 +Feature #5657 - Trial version support +Feature #5707 - User upgrade statistics + v1.8.4-stable ============= - -Bug #4041 UHD/4K DPI scaling broken on Windows servers -Bug #4420 When XRandR adds a screen, it is inaccessible -Bug #5603 Activation notification depends on existence of /etc/os-release -Bug #5624 Update notification sometimes requests a downgrade -Bug #5329 Current date is shown for build date in the about dialog -Bug #5640 Synergy branding is inconsistent across platforms -Enhancement #5617 Remove redundant plugin infrastructure -Enhancement #5627 Move SSL certificate generation to main window -Enhancement #5628 Move SSL implementation into core binary -Enhancement #5629 Move activation from wizard into new dialog window +Bug #5183 - Slowly moving the cursor has no effect on high DPI clients +Bug #4041 - UHD/4K DPI scaling broken on Windows servers +Bug #4420 - When XRandR adds a screen, it is inaccessible +Bug #5603 - Activation notification depends on existence of /etc/os-release +Bug #5624 - Update notification sometimes requests a downgrade +Bug #5329 - Current date is shown for build date in the about dialog +Enhancement #5617 - Remove redundant plugin infrastructure +Enhancement #5627 - Move SSL certificate generation to main window +Enhancement #5628 - Move SSL implementation into core binary +Enhancement #5629 - Move activation from wizard into new dialog window v1.8.3-stable ============= diff --git a/ext/toolchain/commands1.py b/ext/toolchain/commands1.py index 7f357029..9c28ab75 100644 --- a/ext/toolchain/commands1.py +++ b/ext/toolchain/commands1.py @@ -430,14 +430,16 @@ class InternalCommands: if generator.cmakeName.find('Unix Makefiles') != -1: cmake_args += ' -DCMAKE_BUILD_TYPE=' + target.capitalize() - elif sys.platform == "darwin": + if sys.platform == "darwin": macSdkMatch = re.match("(\d+)\.(\d+)", self.macSdk) if not macSdkMatch: raise Exception("unknown osx version: " + self.macSdk) - sdkDir = self.getMacSdkDir() - cmake_args += " -DCMAKE_OSX_SYSROOT=" + sdkDir - cmake_args += " -DCMAKE_OSX_DEPLOYMENT_TARGET=" + self.macSdk + if generator.cmakeName.find('Unix Makefiles') == -1: + sdkDir = self.getMacSdkDir() + cmake_args += " -DCMAKE_OSX_SYSROOT=" + sdkDir + cmake_args += " -DCMAKE_OSX_DEPLOYMENT_TARGET=" + self.macSdk + cmake_args += " -DOSX_TARGET_MAJOR=" + macSdkMatch.group(1) cmake_args += " -DOSX_TARGET_MINOR=" + macSdkMatch.group(2) @@ -551,6 +553,7 @@ class InternalCommands: if os.path.exists(sdkPath): return sdkPath + # return os.popen('xcodebuild -version -sdk macosx' + self.macSdk + ' Path').read().strip() return "/Developer/SDKs/" + sdkDirName + ".sdk" # http://tinyurl.com/cs2rxxb diff --git a/res/synergy.ico b/res/synergy.ico index 9e3d5710..fc2e4146 100644 Binary files a/res/synergy.ico and b/res/synergy.ico differ diff --git a/src/cmd/synergyd/CMakeLists.txt b/src/cmd/synergyd/CMakeLists.txt index 4ee859fc..c8b578a9 100644 --- a/src/cmd/synergyd/CMakeLists.txt +++ b/src/cmd/synergyd/CMakeLists.txt @@ -1,11 +1,11 @@ # synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2012 Nick Bolton -# +# # This package is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # found in the file LICENSE that should have accompanied this file. -# +# # This package 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 @@ -35,7 +35,7 @@ else() endif() target_link_libraries(synergyd - arch base common io ipc mt net platform synergy ${libs} ${OPENSSL_LIBS}) + arch base common io ipc mt net platform synergy shared ${libs} ${OPENSSL_LIBS}) if (WIN32) ADD_CUSTOM_COMMAND( diff --git a/src/gui/gui.pro b/src/gui/gui.pro index c0bf4fad..b60c280d 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -7,7 +7,8 @@ DEFINES += VERSION_REVISION=\\\"$$QMAKE_VERSION_REVISION\\\" DEPENDPATH += . \ res INCLUDEPATH += . \ - src + src \ + ../lib/shared/ FORMS += res/MainWindowBase.ui \ res/AboutDialogBase.ui \ res/ServerConfigDialogBase.ui \ @@ -60,11 +61,12 @@ SOURCES += src/main.cpp \ src/Fingerprint.cpp \ src/SslCertificate.cpp \ src/WebClient.cpp \ - src/SubscriptionManager.cpp \ src/ActivationNotifier.cpp \ src/ActivationDialog.cpp \ src/CancelActivationDialog.cpp \ - src/FailedLoginDialog.cpp + src/FailedLoginDialog.cpp \ + ../lib/shared/SerialKey.cpp \ + src/LicenseManager.cpp HEADERS += src/MainWindow.h \ src/AboutDialog.h \ src/ServerConfig.h \ @@ -101,18 +103,19 @@ HEADERS += src/MainWindow.h \ src/DataDownloader.h \ src/AddClientDialog.h \ src/CommandProcess.h \ - src/EditionType.h \ src/ProcessorArch.h \ src/CoreInterface.h \ src/Fingerprint.h \ src/SslCertificate.h \ src/WebClient.h \ - src/SubscriptionManager.h \ src/ActivationNotifier.h \ src/ElevateMode.h \ src/ActivationDialog.h \ src/CancelActivationDialog.h \ - src/FailedLoginDialog.h + src/FailedLoginDialog.h \ + ../lib/shared/EditionType.h \ + ../lib/shared/SerialKey.h \ + src/LicenseManager.h RESOURCES += res/Synergy.qrc RC_FILE = res/win/Synergy.rc macx { diff --git a/src/gui/res/AboutDialogBase.ui b/src/gui/res/AboutDialogBase.ui index 01df3dd9..ba18e309 100644 --- a/src/gui/res/AboutDialogBase.ui +++ b/src/gui/res/AboutDialogBase.ui @@ -13,19 +13,25 @@ 0 0 450 - 378 + 300 - + 0 0 + + + 450 + 300 + + 450 - 378 + 300 @@ -35,20 +41,48 @@ true - - + + - + 0 0 - + + <p> +Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> +Copyright © 2012-2016 Symless Ltd.<br /> +Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> +Synergy is released under the GNU General Public License (GPLv2).<br /><br /> +Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> +The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> +Visit our website for help and info (symless.com). +</p> + + + 1 + + + + + + + Qt::Vertical + + + QSizePolicy::Preferred + + - 450 - 16777215 + 20 + 100 + + + + @@ -163,41 +197,6 @@ - - - - - 0 - 0 - - - - <html><head/><body><p>Keyboard and mouse sharing application. <br/><br/>Copyright © 2012-2016 Symless Ltd.<br/>Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.</p><p>Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br/>The Synergy GUI is based on QSynergy by Volker Lanz. </p><p>Synergy is released under the GNU General Public License (GPLv2).</p></body></html> - - - false - - - 1 - - - - - - - Qt::Vertical - - - QSizePolicy::Preferred - - - - 20 - 100 - - - - diff --git a/src/gui/res/ActivationDialog.ui b/src/gui/res/ActivationDialog.ui index fb700f91..86fea30d 100644 --- a/src/gui/res/ActivationDialog.ui +++ b/src/gui/res/ActivationDialog.ui @@ -6,8 +6,8 @@ 0 0 - 440 - 314 + 410 + 211 @@ -15,7 +15,7 @@ - + 75 @@ -23,83 +23,14 @@ - &Account login - - - true - - - - - - - QFormLayout::AllNonFixedFieldsGrow - - - 20 - - - 10 - - - - - Email: - - - - - - - - 0 - 0 - - - - QLineEdit::Normal - - - - - - - Password: - - - - - - - - 0 - 0 - - - - QLineEdit::Password - - - - - - - - - - 75 - true - - - - &Serial key + Serial key - Found on your <a href="https://symless.com/account/?source=gui">account</a> page. + <html><head/><body><p>This can be found on your <a href="https://symless.com/account/?source=gui"><span style=" text-decoration: underline; color:#0000ff;">account</span></a> page.</p></body></html> true @@ -109,7 +40,10 @@ - false + true + + + true <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> @@ -123,6 +57,57 @@ p, li { white-space: pre-wrap; } + + + + + 2 + + + 0 + + + 0 + + + 8 + + + + + + + + :/res/icons/16x16/money.png + + + + + + + <html><head/><body><p>Your trial has expired. <a href="http://symless.com/pricing?src=gui"><span style=" text-decoration: underline; color:#0000ff;">Buy now!</span></a></p></body></html> + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + @@ -135,7 +120,12 @@ p, li { white-space: pre-wrap; } - + + m_pTextEditSerialKey + + + + buttonBox diff --git a/src/gui/res/CancelActivationDialog.ui b/src/gui/res/CancelActivationDialog.ui index b98733f6..054b3fe6 100644 --- a/src/gui/res/CancelActivationDialog.ui +++ b/src/gui/res/CancelActivationDialog.ui @@ -19,7 +19,7 @@ Are you sure? -If you don't activate Synergy you'll be missing out on some great features +If you don't activate Synergy you'll be missing out on some great features. true diff --git a/src/gui/res/MainWindowBase.ui b/src/gui/res/MainWindowBase.ui index 87144cd1..b3fb0a75 100644 --- a/src/gui/res/MainWindowBase.ui +++ b/src/gui/res/MainWindowBase.ui @@ -27,6 +27,57 @@ + + + + + 2 + + + 0 + + + 0 + + + 8 + + + + + + + + :/res/icons/16x16/warning.png + + + + + + + <html><head/><body><p><span style=" font-weight:600;">%1</span> days of your Synergy Pro trial remain. <a href="http://symless.com/pricing?src=gui"><span style=" text-decoration: underline; color:#0000ff;">Buy now!</span></a></p></body></html> + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + @@ -40,7 +91,7 @@ 0 - 7 + 8 diff --git a/src/gui/res/ServerConfigDialogBase.ui b/src/gui/res/ServerConfigDialogBase.ui index 1cc4d2b5..5478f360 100644 --- a/src/gui/res/ServerConfigDialogBase.ui +++ b/src/gui/res/ServerConfigDialogBase.ui @@ -17,7 +17,7 @@ - 2 + 0 diff --git a/src/gui/res/icons/256x256/synergy.ico b/src/gui/res/icons/256x256/synergy.ico index 9e3d5710..fc2e4146 100644 Binary files a/src/gui/res/icons/256x256/synergy.ico and b/src/gui/res/icons/256x256/synergy.ico differ diff --git a/src/gui/res/image/about.png b/src/gui/res/image/about.png index 66307bb0..4630bd32 100644 Binary files a/src/gui/res/image/about.png and b/src/gui/res/image/about.png differ diff --git a/src/gui/src/ActivationDialog.cpp b/src/gui/src/ActivationDialog.cpp index 40251019..253ec3ee 100644 --- a/src/gui/src/ActivationDialog.cpp +++ b/src/gui/src/ActivationDialog.cpp @@ -7,159 +7,116 @@ #include "ActivationNotifier.h" #include "MainWindow.h" #include "QUtility.h" -#include "SubscriptionManager.h" +#include "LicenseManager.h" #include "FailedLoginDialog.h" #include #include #include -ActivationDialog::ActivationDialog(QWidget* parent, AppConfig& appConfig) : +ActivationDialog::ActivationDialog(QWidget* parent, AppConfig& appConfig, + LicenseManager& licenseManager) : QDialog(parent), ui(new Ui::ActivationDialog), - m_appConfig (&appConfig) + m_appConfig(&appConfig), + m_LicenseManager (&licenseManager) { ui->setupUi(this); - - ui->m_pLineEditEmail->setText(appConfig.activateEmail()); - ui->m_pTextEditSerialKey->setText(appConfig.serialKey()); - - if (!appConfig.serialKey().isEmpty()) { - ui->m_pRadioButtonActivate->setAutoExclusive(false); - ui->m_pRadioButtonSubscription->setAutoExclusive(false); - ui->m_pRadioButtonActivate->setChecked(false); - ui->m_pRadioButtonSubscription->setChecked(true); - ui->m_pRadioButtonActivate->setAutoExclusive(true); - ui->m_pRadioButtonSubscription->setAutoExclusive(true); - ui->m_pTextEditSerialKey->setFocus(); - ui->m_pTextEditSerialKey->moveCursor(QTextCursor::End); - } else { - if (ui->m_pLineEditEmail->text().isEmpty()) { - ui->m_pLineEditEmail->setFocus(); - } else { - ui->m_pLineEditPassword->setFocus(); - } + refreshSerialKey(); + time_t currentTime = ::time(0); + if (!m_LicenseManager->serialKey().isExpired(currentTime)) { + ui->m_trialWidget->hide(); } } +void ActivationDialog::refreshSerialKey() +{ + ui->m_pTextEditSerialKey->setText(m_appConfig->serialKey()); + ui->m_pTextEditSerialKey->setFocus(); + ui->m_pTextEditSerialKey->moveCursor(QTextCursor::End); + ui->m_trialLabel->setText(tr("

Your trial has " + "expired. Buy now!" + "

") + .arg (m_appConfig->serialKey())); +} + ActivationDialog::~ActivationDialog() { delete ui; } -void ActivationDialog::notifyActivation(QString identity) -{ - ActivationNotifier* notifier = new ActivationNotifier(); - notifier->setIdentity(identity); - - QThread* thread = new QThread(); - connect(notifier, SIGNAL(finished()), thread, SLOT(quit())); - connect(notifier, SIGNAL(finished()), notifier, SLOT(deleteLater())); - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - - notifier->moveToThread(thread); - thread->start(); - - QMetaObject::invokeMethod(notifier, "notify", Qt::QueuedConnection); -} - void ActivationDialog::reject() { - CancelActivationDialog cancelActivationDialog(this); - if (QDialog::Accepted == cancelActivationDialog.exec()) { - notifyActivation("skip:unknown"); - m_appConfig->activationHasRun(true); - m_appConfig->saveSettings(); - QDialog::reject(); - } -} - -void ActivationDialog::on_m_pRadioButtonSubscription_toggled(bool checked) -{ - if (checked) { - ui->m_pLineEditEmail->setEnabled(false); - ui->m_pLineEditPassword->setEnabled(false); - ui->m_pTextEditSerialKey->setEnabled(true); - ui->m_pTextEditSerialKey->setFocus(); - } -} - -void ActivationDialog::on_m_pRadioButtonActivate_toggled(bool checked) -{ - if (checked) { - ui->m_pLineEditEmail->setEnabled(true); - ui->m_pLineEditPassword->setEnabled(true); - ui->m_pTextEditSerialKey->setEnabled(false); - if (ui->m_pLineEditEmail->text().isEmpty()) { - ui->m_pLineEditEmail->setFocus(); + if (m_LicenseManager->activeEdition() == kUnregistered) { + CancelActivationDialog cancelActivationDialog(this); + if (QDialog::Accepted == cancelActivationDialog.exec()) { + m_LicenseManager->skipActivation(); + m_appConfig->activationHasRun(true); + m_appConfig->saveSettings(); } else { - ui->m_pLineEditPassword->setFocus(); + return; } } + QDialog::reject(); } void ActivationDialog::accept() { QMessageBox message; - QString error; - int edition = Unregistered; - m_appConfig->activationHasRun(true); m_appConfig->saveSettings(); + std::pair result; try { - if (ui->m_pRadioButtonActivate->isChecked()) { - WebClient webClient; - QString email = ui->m_pLineEditEmail->text(); - QString password = ui->m_pLineEditPassword->text(); - - if (!webClient.setEmail (email, error)) { - message.critical (this, "Invalid Email Address", tr("%1").arg(error)); - return; - } - else if (!webClient.setPassword (password, error)) { - message.critical (this, "Invalid Password", tr("%1").arg(error)); - return; - } - else if (!webClient.getEdition (edition, error)) { - FailedLoginDialog failedLoginDialog (this, error); - failedLoginDialog.exec(); - return; - } - - m_appConfig->setActivateEmail (email); - m_appConfig->clearSerialKey(); - ui->m_pTextEditSerialKey->clear(); - notifyActivation ("login:" + m_appConfig->activateEmail()); - } - else { - QString serialKey = ui->m_pTextEditSerialKey->toPlainText(); - - if (!m_appConfig->setSerialKey (serialKey, error)) { - message.critical (this, "Invalid Serial Key", tr("%1").arg(error)); - return; - } - - SubscriptionManager subscriptionManager (this, *m_appConfig, edition); - if (!subscriptionManager.activateSerial (serialKey)) { - return; - } - m_appConfig->setActivateEmail(""); - notifyActivation ("serial:" + m_appConfig->serialKey()); - } + QString serialKey = ui->m_pTextEditSerialKey->toPlainText().trimmed(); + result = m_LicenseManager->setSerialKey(serialKey); } catch (std::exception& e) { - message.critical (this, "Unknown Error", + message.critical(this, "Unknown Error", tr("An error occurred while trying to activate Synergy. " "Please contact the helpdesk, and provide the " - "following details.\n\n%1").arg(e.what())); + "following information:\n\n%1").arg(e.what())); + refreshSerialKey(); return; } - m_appConfig->setEdition(edition); - m_appConfig->saveSettings(); + if (!result.first) { + message.critical(this, "Activation failed", + tr("%1").arg(result.second)); + refreshSerialKey(); + return; + } + + m_LicenseManager->notifyActivation("serial:" + m_appConfig->serialKey()); + Edition edition = m_LicenseManager->activeEdition(); + time_t daysLeft = m_LicenseManager->serialKey().daysLeft(::time(0)); + if (edition != kUnregistered) { + QString thanksMessage = tr("Thanks for trying %1! %5\n\n%2 day%3 of " + "your trial remain%4"). + arg (m_LicenseManager->getEditionName(edition)). + arg (daysLeft). + arg ((daysLeft == 1) ? "" : "s"). + arg ((daysLeft == 1) ? "s" : ""); + + if (edition == kPro) { + thanksMessage = thanksMessage.arg("If you're using SSL, " + "remember to activate all of your devices."); + } else { + thanksMessage = thanksMessage.arg(""); + } + + if (m_LicenseManager->serialKey().isTrial()) { + message.information(this, "Thanks!", thanksMessage); + } + else { + message.information(this, "Activated!", + tr("Thanks for activating %1!").arg + (m_LicenseManager->getEditionName(edition))); + } + } - message.information (this, "Activated!", - tr("Thanks for activating %1!").arg (getEditionName (edition))); QDialog::accept(); } diff --git a/src/gui/src/ActivationDialog.h b/src/gui/src/ActivationDialog.h index 6fb926cc..1cc45933 100644 --- a/src/gui/src/ActivationDialog.h +++ b/src/gui/src/ActivationDialog.h @@ -2,6 +2,7 @@ #define ACTIVATIONDIALOG_H #include +#include namespace Ui { class ActivationDialog; @@ -12,9 +13,10 @@ class AppConfig; class ActivationDialog : public QDialog { Q_OBJECT - + public: - explicit ActivationDialog(QWidget *parent, AppConfig& appConfig); + ActivationDialog(QWidget *parent, AppConfig& appConfig, + LicenseManager& licenseManager); ~ActivationDialog(); public slots: @@ -22,15 +24,12 @@ public slots: void accept(); protected: - void notifyActivation (QString identity); - + void refreshSerialKey(); + private: Ui::ActivationDialog *ui; AppConfig* m_appConfig; - -private slots: - void on_m_pRadioButtonSubscription_toggled(bool checked); - void on_m_pRadioButtonActivate_toggled(bool checked); + LicenseManager* m_LicenseManager; }; #endif // ACTIVATIONDIALOG_H diff --git a/src/gui/src/ActivationNotifier.cpp b/src/gui/src/ActivationNotifier.cpp index fb2fd465..0786d90c 100644 --- a/src/gui/src/ActivationNotifier.cpp +++ b/src/gui/src/ActivationNotifier.cpp @@ -20,7 +20,7 @@ #include "CoreInterface.h" ActivationNotifier::ActivationNotifier(QObject *parent) : - QObject(parent) + QObject(parent) { } @@ -29,6 +29,15 @@ void ActivationNotifier::setIdentity(QString identity) m_Identity = identity; } +void ActivationNotifier::setUpdateInfo(QString const& fromVersion, + QString const& toVersion, + QString const& serialKey) +{ + m_fromVersion = fromVersion; + m_toVersion = toVersion; + m_serialKey = serialKey; +} + void ActivationNotifier::notify() { CoreInterface coreInterface; @@ -39,3 +48,13 @@ void ActivationNotifier::notify() // catch all exceptions and fails silently } } + +void ActivationNotifier::notifyUpdate() +{ + try { + CoreInterface coreInterface; + coreInterface.notifyUpdate(m_fromVersion, m_toVersion, + m_serialKey); + } catch (...) { + } +} diff --git a/src/gui/src/ActivationNotifier.h b/src/gui/src/ActivationNotifier.h index d245cd27..2ac216c7 100644 --- a/src/gui/src/ActivationNotifier.h +++ b/src/gui/src/ActivationNotifier.h @@ -24,18 +24,24 @@ class ActivationNotifier : public QObject { Q_OBJECT public: - explicit ActivationNotifier(QObject *parent = 0); + explicit ActivationNotifier(QObject *parent = 0); void setIdentity(QString identity); + void setUpdateInfo(QString const& fromVersion, + QString const& toVersion, QString const& serialKey); public slots: void notify(); + void notifyUpdate(); signals: void finished(); private: QString m_Identity; + QString m_fromVersion; + QString m_toVersion; + QString m_serialKey; }; #endif // ACTIVATIONNOTIFIER_H diff --git a/src/gui/src/AppConfig.cpp b/src/gui/src/AppConfig.cpp index 9848e6b4..06f9f43d 100644 --- a/src/gui/src/AppConfig.cpp +++ b/src/gui/src/AppConfig.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE that should have accompanied this file. - * + * * This package 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 @@ -153,15 +153,16 @@ void AppConfig::loadSettings() QVariant elevateMode = settings().value("elevateModeEnum"); if (!elevateMode.isValid()) { elevateMode = settings().value ("elevateMode", - QVariant(static_cast(defaultElevateMode))); + QVariant(static_cast(defaultElevateMode))); } m_ElevateMode = static_cast(elevateMode.toInt()); m_AutoConfigPrompted = settings().value("autoConfigPrompted", false).toBool(); - m_Edition = settings().value("edition", Unregistered).toInt(); + m_Edition = static_cast(settings().value("edition", kUnregistered).toInt()); m_ActivateEmail = settings().value("activateEmail", "").toString(); m_CryptoEnabled = settings().value("cryptoEnabled", true).toBool(); m_AutoHide = settings().value("autoHide", false).toBool(); m_Serialkey = settings().value("serialKey", "").toString(); + m_lastVersion = settings().value("lastVersion", "Unknown").toString(); m_LastExpiringWarningTime = settings().value("lastExpiringWarningTime", 0).toInt(); m_ActivationHasRun = settings().value("activationHasRun", false).toBool(); } @@ -178,16 +179,16 @@ void AppConfig::saveSettings() settings().setValue("language", m_Language); settings().setValue("startedBefore", m_StartedBefore); settings().setValue("autoConfig", m_AutoConfig); - // Refer to enum ElevateMode declaration for insight in to why this - // flag is mapped this way + // Refer to enum ElevateMode declaration for insight in to why this + // flag is mapped this way settings().setValue("elevateMode", m_ElevateMode == ElevateAlways); settings().setValue("elevateModeEnum", static_cast(m_ElevateMode)); settings().setValue("autoConfigPrompted", m_AutoConfigPrompted); settings().setValue("edition", m_Edition); - settings().setValue("activateEmail", m_ActivateEmail); settings().setValue("cryptoEnabled", m_CryptoEnabled); settings().setValue("autoHide", m_AutoHide); settings().setValue("serialKey", m_Serialkey); + settings().setValue("lastVersion", m_lastVersion); settings().setValue("lastExpiringWarningTime", m_LastExpiringWarningTime); settings().setValue("activationHasRun", m_ActivationHasRun); settings().sync(); @@ -204,6 +205,15 @@ AppConfig& AppConfig::activationHasRun(bool value) return *this; } +QString AppConfig::lastVersion() const +{ + return m_lastVersion; +} + +void AppConfig::setLastVersion(QString version) { + m_lastVersion = version; +} + QSettings &AppConfig::settings() { return *m_pSettings; } void AppConfig::setScreenName(const QString &s) { m_ScreenName = s; } @@ -238,27 +248,16 @@ void AppConfig::setAutoConfigPrompted(bool prompted) m_AutoConfigPrompted = prompted; } -void AppConfig::setEdition(int e) { +void AppConfig::setEdition(Edition e) { m_Edition = e; - emit editionSet (e); } -int AppConfig::edition() const { return m_Edition; } +Edition AppConfig::edition() const { return m_Edition; } -bool AppConfig::setActivateEmail(QString e) { - m_ActivateEmail = e; - return true; -} - -QString AppConfig::activateEmail() { return m_ActivateEmail; } - -bool AppConfig::setSerialKey(QString serial, QString& errorOut) { - if (serial.isEmpty()) { - errorOut = "Your serial key cannot be blank."; - return false; - } - m_Serialkey = serial; - return true; +QString AppConfig::setSerialKey(QString serial) { + using std::swap; + swap (serial, m_Serialkey); + return serial; } void AppConfig::clearSerialKey() @@ -286,8 +285,8 @@ void AppConfig::setCryptoEnabled(bool e) { emit sslToggled(e); } -bool AppConfig::getCryptoEnabled() const { - return (edition() == Pro) && m_CryptoEnabled; +bool AppConfig::getCryptoEnabled() const { + return (edition() == kPro) && m_CryptoEnabled; } void AppConfig::setAutoHide(bool b) { m_AutoHide = b; } diff --git a/src/gui/src/AppConfig.h b/src/gui/src/AppConfig.h index 271ef683..4dcd4572 100644 --- a/src/gui/src/AppConfig.h +++ b/src/gui/src/AppConfig.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE that should have accompanied this file. - * + * * This package 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 @@ -23,6 +23,7 @@ #include #include #include "ElevateMode.h" +#include // this should be incremented each time a new page is added. this is // saved to settings when the user finishes running the wizard. if @@ -77,11 +78,9 @@ class AppConfig: public QObject void setAutoConfig(bool autoConfig); bool autoConfigPrompted(); void setAutoConfigPrompted(bool prompted); - void setEdition(int e); - int edition() const; - bool setActivateEmail(QString e); - QString activateEmail(); - bool setSerialKey(QString serial, QString& error); + void setEdition(Edition); + Edition edition() const; + QString setSerialKey(QString serial); void clearSerialKey(); QString serialKey(); int lastExpiringWarningTime() const; @@ -105,9 +104,12 @@ class AppConfig: public QObject bool activationHasRun() const; AppConfig& activationHasRun(bool value); - void saveSettings(); + QString lastVersion() const; - protected: + void saveSettings(); + void setLastVersion(QString version); + +protected: QSettings& settings(); void setScreenName(const QString& s); void setPort(int i); @@ -136,11 +138,12 @@ class AppConfig: public QObject bool m_AutoConfig; ElevateMode m_ElevateMode; bool m_AutoConfigPrompted; - int m_Edition; + Edition m_Edition; QString m_ActivateEmail; bool m_CryptoEnabled; bool m_AutoHide; QString m_Serialkey; + QString m_lastVersion; int m_LastExpiringWarningTime; bool m_ActivationHasRun; @@ -149,7 +152,6 @@ class AppConfig: public QObject static const char m_SynergyLogDir[]; signals: - void editionSet(int); void sslToggled(bool enabled); }; diff --git a/src/gui/src/CoreInterface.cpp b/src/gui/src/CoreInterface.cpp index d537a24f..e560fc45 100644 --- a/src/gui/src/CoreInterface.cpp +++ b/src/gui/src/CoreInterface.cpp @@ -22,20 +22,22 @@ #include #include +#include +#include #include static const char kCoreBinary[] = "syntool"; +#ifdef Q_WS_WIN +static const char kSerialKeyFilename[] = "Synergy.subkey"; +#else +static const char kSerialKeyFilename[] = ".synergy.subkey"; +#endif + CoreInterface::CoreInterface() { } -QString CoreInterface::getPluginDir() -{ - QStringList args("--get-plugin-dir"); - return run(args); -} - QString CoreInterface::getProfileDir() { QStringList args("--get-profile-dir"); @@ -54,24 +56,19 @@ QString CoreInterface::getArch() return run(args); } -QString CoreInterface::getSubscriptionFilename() +QString CoreInterface::getSerialKeyFilePath() { - QStringList args("--get-subscription-filename"); - return run(args); + QString filename = getProfileDir() + QDir::separator() + kSerialKeyFilename; + return filename; } -QString CoreInterface::activateSerial(const QString& serial) -{ - QStringList args("--subscription-serial"); - args << serial; - - return run(args); -} - -QString CoreInterface::checkSubscription() -{ - QStringList args("--check-subscription"); - return run(args); +QString CoreInterface::notifyUpdate (QString const& fromVersion, + QString const& toVersion, + QString const& serialKey) { + QStringList args("--notify-update"); + QString input(fromVersion + ":" + toVersion + ":" + serialKey); + input.append("\n"); + return run(args, input); } QString CoreInterface::notifyActivation(const QString& identity) diff --git a/src/gui/src/CoreInterface.h b/src/gui/src/CoreInterface.h index 13e8fd87..98a84f57 100644 --- a/src/gui/src/CoreInterface.h +++ b/src/gui/src/CoreInterface.h @@ -24,13 +24,13 @@ class CoreInterface public: CoreInterface(); - QString getPluginDir(); QString getProfileDir(); QString getInstalledDir(); QString getArch(); - QString getSubscriptionFilename(); - QString activateSerial(const QString& serial); - QString checkSubscription(); + QString getSerialKeyFilePath(); QString notifyActivation(const QString& identity); + QString notifyUpdate (QString const& fromVersion, + QString const& toVersion, + QString const& serialKey); QString run(const QStringList& args, const QString& input = ""); }; diff --git a/src/gui/src/LicenseManager.cpp b/src/gui/src/LicenseManager.cpp new file mode 100644 index 00000000..221fd16d --- /dev/null +++ b/src/gui/src/LicenseManager.cpp @@ -0,0 +1,163 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2015 Synergy Seamless Inc. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package 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 this program. If not, see . + */ + +#include "LicenseManager.h" +#include "EditionType.h" +#include "AppConfig.h" +#include +#include +#include +#include + +LicenseManager::LicenseManager(AppConfig* appConfig) : + m_AppConfig(appConfig), + m_serialKey(appConfig->edition()) { +} + +std::pair +LicenseManager::setSerialKey(QString serialKeyString, bool acceptExpired) +{ + std::pair ret (true, ""); + time_t currentTime = ::time(0); + SerialKey serialKey (serialKeyString.toStdString()); + + if (!acceptExpired && serialKey.isExpired(currentTime)) { + ret.first = false; + ret.second = "Serial key expired"; + return ret; + } + + if (serialKey != m_serialKey) { + using std::swap; + swap (serialKey, m_serialKey); + m_AppConfig->setSerialKey(serialKeyString); + emit serialKeyChanged(m_serialKey); + + if (serialKey.isTrial()) { + emit endTrial(false); + } + + if (m_serialKey.edition() != serialKey.edition()) { + m_AppConfig->setEdition(m_serialKey.edition()); + emit editionChanged(m_serialKey.edition()); + } + + if (m_serialKey.isTrial()) { + if (m_serialKey.isExpired(currentTime)) { + emit endTrial(true); + } else { + emit beginTrial(m_serialKey.isExpiring(currentTime)); + } + } + + m_AppConfig->saveSettings(); + } + + return ret; +} + +void +LicenseManager::notifyUpdate(QString fromVersion, QString toVersion) { + if ((fromVersion == "Unknown") + && (m_serialKey == SerialKey(kUnregistered))) { + return; + } + + ActivationNotifier* notifier = new ActivationNotifier(); + notifier->setUpdateInfo (fromVersion, toVersion, + QString::fromStdString(m_serialKey.toString())); + + QThread* thread = new QThread(); + connect(notifier, SIGNAL(finished()), thread, SLOT(quit())); + connect(notifier, SIGNAL(finished()), notifier, SLOT(deleteLater())); + connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + + notifier->moveToThread(thread); + thread->start(); + + QMetaObject::invokeMethod(notifier, "notifyUpdate", + Qt::QueuedConnection); +} + +Edition +LicenseManager::activeEdition() const +{ + return m_serialKey.edition(); +} + +QString +LicenseManager::activeEditionName() const +{ + return getEditionName(activeEdition(), m_serialKey.isTrial()); +} + +SerialKey +LicenseManager::serialKey() const +{ + return m_serialKey; +} + +void LicenseManager::refresh() +{ + if (!m_AppConfig->serialKey().isEmpty()) { + setSerialKey(m_AppConfig->serialKey(), true); + } + if (m_serialKey.isExpired(::time(0))) { + emit endTrial(true); + } +} + +void LicenseManager::skipActivation() +{ + notifyActivation ("skip:unknown"); +} + +QString +LicenseManager::getEditionName(Edition const edition, bool trial) +{ + std::string name ("Synergy"); + switch (edition) { + case kUnregistered: + name += " (UNREGISTERED)"; + return QString::fromUtf8 (name.c_str(), name.size()); + case kBasic: + name += " Basic"; + break; + default: + name += " Pro"; + } + if (trial) { + name += " (Trial)"; + } + return QString::fromUtf8 (name.c_str(), name.size()); +} + +void LicenseManager::notifyActivation(QString identity) +{ + ActivationNotifier* notifier = new ActivationNotifier(); + notifier->setIdentity(identity); + + QThread* thread = new QThread(); + connect(notifier, SIGNAL(finished()), thread, SLOT(quit())); + connect(notifier, SIGNAL(finished()), notifier, SLOT(deleteLater())); + connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + + notifier->moveToThread(thread); + thread->start(); + + QMetaObject::invokeMethod(notifier, "notify", Qt::QueuedConnection); +} diff --git a/src/gui/src/LicenseManager.h b/src/gui/src/LicenseManager.h new file mode 100644 index 00000000..2dc89cd8 --- /dev/null +++ b/src/gui/src/LicenseManager.h @@ -0,0 +1,52 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2015 Synergy Seamless Inc. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package 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 this program. If not, see . + */ + +#pragma once + +#include +#include +#include +#include + +class AppConfig; + +class LicenseManager: public QObject +{ + Q_OBJECT + +public: + LicenseManager(AppConfig* appConfig); + std::pair setSerialKey(QString serialKey, bool acceptExpired = false); + void refresh(); + Edition activeEdition() const; + QString activeEditionName() const; + SerialKey serialKey() const; + void skipActivation(); + void notifyUpdate(QString fromVersion, QString toVersion); + static QString getEditionName(Edition edition, bool trial = false); + void notifyActivation(QString identity); + +private: + AppConfig* m_AppConfig; + SerialKey m_serialKey; + +signals: + void serialKeyChanged (SerialKey) const; + void editionChanged (Edition) const; + void beginTrial (bool expiring) const; + void endTrial (bool expired) const; +}; diff --git a/src/gui/src/MainWindow.cpp b/src/gui/src/MainWindow.cpp index f9903a12..f32ebdc8 100644 --- a/src/gui/src/MainWindow.cpp +++ b/src/gui/src/MainWindow.cpp @@ -30,7 +30,7 @@ #include "ZeroconfService.h" #include "DataDownloader.h" #include "CommandProcess.h" -#include "SubscriptionManager.h" +#include "LicenseManager.h" #include "EditionType.h" #include "QUtility.h" #include "ProcessorArch.h" @@ -76,12 +76,14 @@ static const char* synergyIconFiles[] = ":/res/icons/16x16/synergy-transfering.png" }; -MainWindow::MainWindow(QSettings& settings, AppConfig& appConfig) : +MainWindow::MainWindow(QSettings& settings, AppConfig& appConfig, + LicenseManager& licenseManager) : m_Settings(settings), - m_AppConfig(appConfig), + m_AppConfig(&appConfig), + m_LicenseManager(&licenseManager), m_pSynergy(NULL), m_SynergyState(synergyDisconnected), - m_ServerConfig(&m_Settings, 5, 3, m_AppConfig.screenName(), this), + m_ServerConfig(&m_Settings, 5, 3, m_AppConfig->screenName(), this), m_pTempConfigFile(NULL), m_pTrayIcon(NULL), m_pTrayIconMenu(NULL), @@ -99,7 +101,8 @@ MainWindow::MainWindow(QSettings& settings, AppConfig& appConfig) : m_BonjourInstall(NULL), m_SuppressEmptyServerWarning(false), m_ExpectedRunningState(kStopped), - m_pSslCertificate(NULL) + m_pSslCertificate(NULL), + m_ActivationDialogRunning(false) { setupUi(this); @@ -134,13 +137,34 @@ MainWindow::MainWindow(QSettings& settings, AppConfig& appConfig) : m_SuppressAutoConfigWarning = false; m_pComboServerList->hide(); - - setEdition(m_AppConfig.edition()); - m_pLabelPadlock->hide(); - connect (this, SIGNAL(windowShown()), this, SLOT(on_windowShown()), Qt::QueuedConnection); - connect (&m_AppConfig, SIGNAL(editionSet(int)), this, SLOT(setEdition(int)), Qt::QueuedConnection); - connect (&m_AppConfig, SIGNAL(sslToggled(bool)), this, SLOT(sslToggled(bool)), Qt::QueuedConnection); + m_trialWidget->hide(); + + connect (this, SIGNAL(windowShown()), + this, SLOT(on_windowShown()), Qt::QueuedConnection); + + connect (m_LicenseManager, SIGNAL(editionChanged(Edition)), + this, SLOT(setEdition(Edition)), Qt::QueuedConnection); + + connect (m_LicenseManager, SIGNAL(beginTrial(bool)), + this, SLOT(beginTrial(bool)), Qt::QueuedConnection); + + connect (m_LicenseManager, SIGNAL(endTrial(bool)), + this, SLOT(endTrial(bool)), Qt::QueuedConnection); + + connect (m_AppConfig, SIGNAL(sslToggled(bool)), + this, SLOT(sslToggled(bool)), Qt::QueuedConnection); + + setWindowTitle (m_LicenseManager->activeEditionName()); + m_LicenseManager->refresh(); + + QString lastVersion = m_AppConfig->lastVersion(); + QString currentVersion = m_VersionChecker.getVersion(); + if (lastVersion != currentVersion) { + m_AppConfig->setLastVersion (currentVersion); + m_AppConfig->saveSettings(); + m_LicenseManager->notifyUpdate (lastVersion, currentVersion); + } } MainWindow::~MainWindow() @@ -397,15 +421,17 @@ void MainWindow::appendLogRaw(const QString& text) foreach(QString line, text.split(QRegExp("\r|\n|\r\n"))) { if (!line.isEmpty()) { m_pLogOutput->append(line); - updateStateFromLogLine(line); + updateFromLogLine(line); } } } -void MainWindow::updateStateFromLogLine(const QString &line) +void MainWindow::updateFromLogLine(const QString &line) { + // TODO: this code makes Andrew cry checkConnected(line); checkFingerprint(line); + checkLicense(line); } void MainWindow::checkConnected(const QString& line) @@ -430,6 +456,14 @@ void MainWindow::checkConnected(const QString& line) } } +void MainWindow::checkLicense(const QString &line) +{ + if (line.contains("trial has expired")) { + licenseManager().refresh(); + raiseActivationDialog(); + } +} + void MainWindow::checkFingerprint(const QString& line) { QRegExp fingerprintRegex(".*server fingerprint: ([A-F0-9:]+)"); @@ -498,7 +532,7 @@ void MainWindow::restartSynergy() void MainWindow::proofreadInfo() { - setEdition(m_AppConfig.edition()); // Why is this here? + setEdition(m_AppConfig->edition()); // Why is this here? int oldState = m_SynergyState; m_SynergyState = synergyDisconnected; @@ -518,6 +552,14 @@ void MainWindow::clearLog() void MainWindow::startSynergy() { + SerialKey serialKey = m_LicenseManager->serialKey(); + time_t currentTime = ::time(0); + if (serialKey.isExpired(currentTime)) { + if (QDialog::Rejected == raiseActivationDialog()) { + return; + } + } + bool desktopMode = appConfig().processMode() == Desktop; bool serviceMode = appConfig().processMode() == Service; @@ -566,7 +608,7 @@ void MainWindow::startSynergy() #endif - if (m_AppConfig.getCryptoEnabled()) { + if (m_AppConfig->getCryptoEnabled()) { args << "--enable-crypto"; } @@ -734,19 +776,6 @@ QString MainWindow::appPath(const QString& name) bool MainWindow::serverArgs(QStringList& args, QString& app) { - int edition; - SubscriptionManager subscriptionManager(this, appConfig(), edition); - if (subscriptionManager.fileExists()) - { - if (!subscriptionManager.checkSubscription()) { - return false; - } - else { - setEdition(edition); - } - } - - app = appPath(appConfig().synergysName()); if (!QFile::exists(app)) @@ -775,6 +804,10 @@ bool MainWindow::serverArgs(QStringList& args, QString& app) #endif args << "-c" << configFilename << "--address" << address(); + if (!appConfig().serialKey().isEmpty()) { + args << "--serial-key" << appConfig().serialKey(); + } + #if defined(Q_OS_WIN) // pass in physical resolution and primary screen center // TODO: get this information in the core binary even when @@ -895,7 +928,7 @@ void MainWindow::setSynergyState(qSynergyState state) switch (state) { case synergyConnected: { - if (m_AppConfig.getCryptoEnabled()) { + if (m_AppConfig->getCryptoEnabled()) { m_pLabelPadlock->show(); } else { @@ -1010,13 +1043,13 @@ void MainWindow::updateZeroconfService() QMutexLocker locker(&m_UpdateZeroconfMutex); if (isBonjourRunning()) { - if (!m_AppConfig.wizardShouldRun()) { + if (!m_AppConfig->wizardShouldRun()) { if (m_pZeroconfService) { delete m_pZeroconfService; m_pZeroconfService = NULL; } - if (m_AppConfig.autoConfig() || synergyType() == synergyServer) { + if (m_AppConfig->autoConfig() || synergyType() == synergyServer) { m_pZeroconfService = new ZeroconfService(this); } } @@ -1035,10 +1068,10 @@ void MainWindow::serverDetected(const QString name) } } -void MainWindow::setEdition(int edition) +void MainWindow::setEdition(Edition edition) { - setWindowTitle(getEditionName(edition)); - if (m_AppConfig.getCryptoEnabled()) { + setWindowTitle(m_LicenseManager->getEditionName (edition)); + if (m_AppConfig->getCryptoEnabled()) { m_pSslCertificate = new SslCertificate(this); m_pSslCertificate->generateCertificate(); } @@ -1046,9 +1079,60 @@ void MainWindow::setEdition(int edition) saveSettings(); } +void MainWindow::beginTrial(bool isExpiring) +{ + //Hack + //if (isExpiring) { + time_t daysLeft = m_LicenseManager->serialKey().daysLeft(::time(0)); + QString expiringNotice ("

%1 day%3 of " + "your %2 trial remain%5. " + "Buy now!" + "

"); + expiringNotice = expiringNotice + .arg (daysLeft) + .arg (LicenseManager::getEditionName + (m_LicenseManager->activeEdition())) + .arg ((daysLeft == 1) ? "" : "s") + .arg (QString::fromStdString + (m_LicenseManager->serialKey().toString())) + .arg ((daysLeft == 1) ? "s" : ""); + this->m_trialLabel->setText(expiringNotice); + this->m_trialWidget->show(); + //} + setWindowTitle (m_LicenseManager->activeEditionName()); +} + +void MainWindow::endTrial(bool isExpired) +{ + if (isExpired) { + QString expiredNotice ( + "

Your %1 trial has expired. " + "" + "Buy now!

" + ); + expiredNotice = expiredNotice + .arg(LicenseManager::getEditionName + (m_LicenseManager->activeEdition())) + .arg(QString::fromStdString + (m_LicenseManager->serialKey().toString())); + + this->m_trialLabel->setText(expiredNotice); + this->m_trialWidget->show(); + stopSynergy(); + m_AppConfig->activationHasRun(false); + } else { + this->m_trialWidget->hide(); + } + setWindowTitle (m_LicenseManager->activeEditionName()); +} + void MainWindow::updateLocalFingerprint() { - if (m_AppConfig.getCryptoEnabled() && Fingerprint::local().fileExists()) { + if (m_AppConfig->getCryptoEnabled() && Fingerprint::local().fileExists()) { m_pLabelFingerprint->setVisible(true); m_pLabelLocalFingerprint->setVisible(true); m_pLabelLocalFingerprint->setText(Fingerprint::local().readFirst()); @@ -1059,6 +1143,12 @@ void MainWindow::updateLocalFingerprint() } } +LicenseManager& +MainWindow::licenseManager() const +{ + return *m_LicenseManager; +} + void MainWindow::on_m_pGroupClient_toggled(bool on) { m_pGroupServer->setChecked(!on); @@ -1123,6 +1213,14 @@ void MainWindow::on_m_pActionSettings_triggered() void MainWindow::autoAddScreen(const QString name) { if (!m_ServerConfig.ignoreAutoConfigClient()) { + if (m_ActivationDialogRunning) { + // TODO: refactor this code + // add this screen to the pending list and check this list until + // users finish activation dialog + m_PendingClientNames.append(name); + return; + } + int r = m_ServerConfig.autoAddScreen(name); if (r != kAutoAddScreenOk) { switch (r) { @@ -1160,8 +1258,7 @@ void MainWindow::on_m_pButtonConfigureServer_clicked() void MainWindow::on_m_pActivate_triggered() { - ActivationDialog activationDialog (this, this->appConfig()); - activationDialog.exec(); + raiseActivationDialog(); } void MainWindow::on_m_pButtonApply_clicked() @@ -1321,16 +1418,16 @@ void MainWindow::promptAutoConfig() QMessageBox::Yes | QMessageBox::No); if (r == QMessageBox::Yes) { - m_AppConfig.setAutoConfig(true); + m_AppConfig->setAutoConfig(true); downloadBonjour(); } else { - m_AppConfig.setAutoConfig(false); + m_AppConfig->setAutoConfig(false); m_pCheckBoxAutoConfig->setChecked(false); } } - m_AppConfig.setAutoConfigPrompted(true); + m_AppConfig->setAutoConfigPrompted(true); } void MainWindow::on_m_pComboServerList_currentIndexChanged(QString ) @@ -1376,11 +1473,37 @@ void MainWindow::bonjourInstallFinished() m_pCheckBoxAutoConfig->setChecked(true); } +int MainWindow::raiseActivationDialog() +{ + if (m_ActivationDialogRunning) { + return QDialog::Rejected; + } + ActivationDialog activationDialog (this, appConfig(), licenseManager()); + m_ActivationDialogRunning = true; + connect (&activationDialog, SIGNAL(finished(int)), + this, SLOT(on_activationDialogFinish()), Qt::QueuedConnection); + int result = activationDialog.exec(); + m_ActivationDialogRunning = false; + if (!m_PendingClientNames.empty()) { + foreach (const QString& name, m_PendingClientNames) { + autoAddScreen(name); + } + + m_PendingClientNames.clear(); + } + if (result == QDialog::Accepted) { + restartSynergy(); + } + return result; +} + void MainWindow::on_windowShown() { - if (!m_AppConfig.activationHasRun() && (m_AppConfig.edition() == Unregistered)) { - ActivationDialog activationDialog (this, m_AppConfig); - activationDialog.exec(); + time_t currentTime = ::time(0); + if (!m_AppConfig->activationHasRun() + && ((m_AppConfig->edition() == kUnregistered) || + (m_LicenseManager->serialKey().isExpired(currentTime)))) { + raiseActivationDialog(); } } diff --git a/src/gui/src/MainWindow.h b/src/gui/src/MainWindow.h index efd83dcc..2ca3e711 100644 --- a/src/gui/src/MainWindow.h +++ b/src/gui/src/MainWindow.h @@ -58,6 +58,7 @@ class ZeroconfService; class DataDownloader; class CommandProcess; class SslCertificate; +class LicenseManager; class MainWindow : public QMainWindow, public Ui::MainWindowBase { @@ -67,7 +68,7 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase friend class SetupWizard; friend class ActivationDialog; friend class SettingsDialog; - + public: enum qSynergyState { @@ -94,7 +95,8 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase }; public: - MainWindow(QSettings& settings, AppConfig& appConfig); + MainWindow(QSettings& settings, AppConfig& appConfig, + LicenseManager& licenseManager); ~MainWindow(); public: @@ -116,9 +118,14 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase void updateZeroconfService(); void serverDetected(const QString name); void updateLocalFingerprint(); + LicenseManager& licenseManager() const; - public slots: - void setEdition(int edition); + int raiseActivationDialog(); + +public slots: + void setEdition(Edition edition); + void beginTrial(bool isExpiring); + void endTrial(bool isExpired); void appendLogRaw(const QString& text); void appendLogInfo(const QString& text); void appendLogDebug(const QString& text); @@ -145,7 +152,7 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase protected: QSettings& settings() { return m_Settings; } - AppConfig& appConfig() { return m_AppConfig; } + AppConfig& appConfig() { return *m_AppConfig; } QProcess* synergyProcess() { return m_pSynergy; } void setSynergyProcess(QProcess* p) { m_pSynergy = p; } void initConnections(); @@ -162,7 +169,7 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase void setStatus(const QString& status); void sendIpcMessage(qIpcMessageType type, const char* buffer, bool showErrors); void onModeChanged(bool startDesktop, bool applyService); - void updateStateFromLogLine(const QString& line); + void updateFromLogLine(const QString& line); QString getIPAddresses(); void stopService(); void stopDesktop(); @@ -178,6 +185,7 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase void promptAutoConfig(); QString getProfileRootForArg(); void checkConnected(const QString& line); + void checkLicense(const QString& line); void checkFingerprint(const QString& line); bool autoHide(); QString getTimeStamp(); @@ -188,7 +196,8 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase private: QSettings& m_Settings; - AppConfig& m_AppConfig; + AppConfig* m_AppConfig; + LicenseManager* m_LicenseManager; QProcess* m_pSynergy; int m_SynergyState; ServerConfig m_ServerConfig; @@ -214,6 +223,8 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase qRuningState m_ExpectedRunningState; QMutex m_StopDesktopMutex; SslCertificate* m_pSslCertificate; + bool m_ActivationDialogRunning; + QStringList m_PendingClientNames; private slots: void on_m_pCheckBoxAutoConfig_toggled(bool checked); diff --git a/src/gui/src/QUtility.cpp b/src/gui/src/QUtility.cpp index f463f1d2..589e74cf 100644 --- a/src/gui/src/QUtility.cpp +++ b/src/gui/src/QUtility.cpp @@ -43,22 +43,6 @@ void setIndexFromItemData(QComboBox* comboBox, const QVariant& itemData) } } -QString -getEditionName (int edition) { - if (edition == Basic) { - return "Synergy Basic"; - } - else if (edition == Pro) { - return "Synergy Pro"; - } - else if (edition == Trial) { - return "Synergy Trial"; - } - else { - return "Synergy (UNREGISTERED)"; - } -} - QString hash(const QString& string) { QByteArray data = string.toUtf8(); diff --git a/src/gui/src/QUtility.h b/src/gui/src/QUtility.h index ca00d06f..0738d96c 100644 --- a/src/gui/src/QUtility.h +++ b/src/gui/src/QUtility.h @@ -29,4 +29,3 @@ QString hash(const QString& string); QString getFirstMacAddress(); qProcessorArch getProcessorArch(); QString getOSInformation(); -QString getEditionName (int edition); diff --git a/src/gui/src/SettingsDialog.cpp b/src/gui/src/SettingsDialog.cpp index 9b1d1b0e..ddbeae4d 100644 --- a/src/gui/src/SettingsDialog.cpp +++ b/src/gui/src/SettingsDialog.cpp @@ -64,7 +64,7 @@ SettingsDialog::SettingsDialog(QWidget* parent, AppConfig& config) : #endif m_pCheckBoxEnableCrypto->setChecked(m_appConfig.getCryptoEnabled()); - m_pCheckBoxEnableCrypto->setEnabled(m_appConfig.edition() == Pro); + m_pCheckBoxEnableCrypto->setEnabled(m_appConfig.edition() == kPro); } void SettingsDialog::accept() diff --git a/src/gui/src/SetupWizard.cpp b/src/gui/src/SetupWizard.cpp index b4e6ab3a..da3ff8c3 100644 --- a/src/gui/src/SetupWizard.cpp +++ b/src/gui/src/SetupWizard.cpp @@ -19,7 +19,7 @@ #include "MainWindow.h" #include "WebClient.h" #include "ActivationNotifier.h" -#include "SubscriptionManager.h" +#include "LicenseManager.h" #include "EditionType.h" #include "QSynergyApplication.h" #include "QUtility.h" diff --git a/src/gui/src/SubscriptionManager.cpp b/src/gui/src/SubscriptionManager.cpp deleted file mode 100644 index 77e0a91c..00000000 --- a/src/gui/src/SubscriptionManager.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/* - * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2015 Synergy Seamless Inc. - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * found in the file LICENSE that should have accompanied this file. - * - * This package 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 this program. If not, see . - */ - -#include "SubscriptionManager.h" - - -#include "CoreInterface.h" -#include "EditionType.h" -#include "AppConfig.h" - -#include -#include -#include -#include -#include - -static const char purchaseURL[] = "https://symless.com/account/"; - -SubscriptionManager::SubscriptionManager(QWidget* parent, AppConfig& appConfig, int& edition) : - m_pParent(parent), - m_AppConfig(appConfig), - m_Edition(edition) -{ -} - -bool SubscriptionManager::activateSerial(const QString& serial) -{ - m_Edition = Unregistered; - persistDirectory(); - CoreInterface coreInterface; - QString output; - - try - { - output = coreInterface.activateSerial(serial); - } - catch (std::exception& e) - { - m_ErrorMessage = e.what(); - checkError(m_ErrorMessage); - return false; - } - - checkOutput(output); - - return true; -} - -bool SubscriptionManager::checkSubscription() -{ - m_Edition = Unregistered; - persistDirectory(); - CoreInterface coreInterface; - QString output; - try - { - output = coreInterface.checkSubscription(); - } - catch (std::exception& e) - { - m_ErrorMessage = e.what(); - checkError(m_ErrorMessage); - return false; - } - - checkOutput(output); - - return true; -} - -bool SubscriptionManager::fileExists() -{ - CoreInterface coreInterface; - QString subscriptionFilename = coreInterface.getSubscriptionFilename(); - - return QFile::exists(subscriptionFilename); -} - -void SubscriptionManager::checkError(QString& error) -{ - if (error.contains("trial has expired")) { - QMessageBox::warning(m_pParent, tr("Subscription warning"), - tr("Your trial has expired. Click here to purchase").arg(purchaseURL)); - } - else { - QMessageBox::warning(m_pParent, tr("Subscription error"), - tr("An error occurred while trying to activate Synergy using your serial key. " - "Please contact the helpdesk, and provide the " - "following details.\n\n%1").arg(error)); - } -} - -void SubscriptionManager::checkOutput(QString& output) -{ - getEditionType(output); - checkExpiring(output); -} - -void SubscriptionManager::getEditionType(QString& output) -{ - if (output.contains("pro subscription valid")) { - m_Edition = Pro; - } - else if (output.contains("basic subscription valid")) { - m_Edition = Basic; - } - else if (output.contains("trial subscription valid")) { - m_Edition = Trial; - } -} - -void SubscriptionManager::checkExpiring(QString& output) -{ - if (output.contains("trial will end in") && shouldWarnExpiring()) { - QRegExp dayLeftRegex(".*trial will end in ([0-9]+) day.*"); - if (dayLeftRegex.exactMatch(output)) { - QString dayLeft = dayLeftRegex.cap(1); - - QMessageBox::warning(m_pParent, tr("Subscription warning"), - tr("Your trial will end in %1 %2. Click here to purchase") - .arg(dayLeft) - .arg(dayLeft == "1" ? "day" : "days") - .arg(purchaseURL)); - } - } -} - -bool SubscriptionManager::shouldWarnExpiring() -{ - // warn users about expiring subscription once a day - int lastExpiringWarningTime = m_AppConfig.lastExpiringWarningTime(); - QDateTime currentDateTime = QDateTime::currentDateTime(); - int currentTime = currentDateTime.toTime_t(); - const int secondPerDay = 60 * 60 * 24; - bool result = false; - if ((currentTime - lastExpiringWarningTime) > secondPerDay) { - result = true; - m_AppConfig.setLastExpiringWarningTime(currentTime); - } - - return result; -} - -void SubscriptionManager::persistDirectory() -{ - CoreInterface coreInterface; - QString profileDir = coreInterface.getProfileDir(); - - QDir dir(profileDir); - if (!dir.exists()) { - dir.mkpath("."); - } -} diff --git a/src/gui/src/SubscriptionManager.h b/src/gui/src/SubscriptionManager.h deleted file mode 100644 index 59497352..00000000 --- a/src/gui/src/SubscriptionManager.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2015 Synergy Seamless Inc. - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * found in the file LICENSE that should have accompanied this file. - * - * This package 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 this program. If not, see . - */ - -#pragma once - -#include - -class AppConfig; - -class SubscriptionManager : public QWidget -{ -public: - SubscriptionManager(QWidget* parent, AppConfig& appConfig, int& edition); - - bool activateSerial(const QString& serial); - bool checkSubscription(); - bool fileExists(); - QString getLastError(){ return m_ErrorMessage; } - -private: - void checkError(QString& error); - void checkOutput(QString& output); - void getEditionType(QString& output); - void checkExpiring(QString& output); - bool shouldWarnExpiring(); - void persistDirectory(); - -private: - QString m_ErrorMessage; - QWidget* m_pParent; - AppConfig& m_AppConfig; - int& m_Edition; -}; diff --git a/src/gui/src/main.cpp b/src/gui/src/main.cpp index 0ea2cbfe..d36db755 100644 --- a/src/gui/src/main.cpp +++ b/src/gui/src/main.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE that should have accompanied this file. - * + * * This package 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 @@ -20,6 +20,7 @@ #define TRAY_RETRY_WAIT 2000 #include "QSynergyApplication.h" +#include "LicenseManager.h" #include "MainWindow.h" #include "AppConfig.h" #include "SetupWizard.h" @@ -65,7 +66,7 @@ int main(int argc, char* argv[]) "Please drag Synergy to the Applications folder, and open it from there."); return 1; } - + if (!checkMacAssistiveDevices()) { return 1; @@ -82,11 +83,13 @@ int main(int argc, char* argv[]) #endif QSettings settings; - AppConfig appConfig(&settings); + AppConfig appConfig (&settings); + qRegisterMetaType("Edition"); + LicenseManager licenseManager (&appConfig); app.switchTranslator(appConfig.language()); - MainWindow mainWindow(settings, appConfig); + MainWindow mainWindow(settings, appConfig, licenseManager); SetupWizard setupWizard(mainWindow, true); if (appConfig.wizardShouldRun()) diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 48beb80a..f53d9db8 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -25,7 +25,7 @@ add_subdirectory(net) add_subdirectory(platform) add_subdirectory(server) add_subdirectory(synergy) - +add_subdirectory(shared) if (WIN32) add_subdirectory(synwinhk) diff --git a/src/lib/arch/unix/ArchInternetUnix.cpp b/src/lib/arch/unix/ArchInternetUnix.cpp index 596000c1..fe4a39ba 100644 --- a/src/lib/arch/unix/ArchInternetUnix.cpp +++ b/src/lib/arch/unix/ArchInternetUnix.cpp @@ -116,7 +116,6 @@ CurlFacade::urlEncode(const String& url) char* resultCStr = curl_easy_escape(m_curl, url.c_str(), 0); if (resultCStr == NULL) { - curl_free(resultCStr); throw XArch("CURL escape failed."); } diff --git a/src/lib/net/IListenSocket.h b/src/lib/net/IListenSocket.h index 905ec831..2cd6fb1b 100644 --- a/src/lib/net/IListenSocket.h +++ b/src/lib/net/IListenSocket.h @@ -41,14 +41,7 @@ public: */ virtual IDataSocket* accept() = 0; - - //! Delete connection socket - /*! - This is used when the socket was created but not adopted by a client - proxy. - */ - virtual void deleteSocket(void*) = 0; - + //@} // ISocket overrides diff --git a/src/lib/net/SecureListenSocket.cpp b/src/lib/net/SecureListenSocket.cpp index b4c08646..533ae41a 100644 --- a/src/lib/net/SecureListenSocket.cpp +++ b/src/lib/net/SecureListenSocket.cpp @@ -93,14 +93,3 @@ SecureListenSocket::accept() throw ex; } } - -void -SecureListenSocket::deleteSocket(void* socket) -{ - SecureSocketSet::iterator it; - it = m_secureSocketSet.find((IDataSocket*)socket); - if (it != m_secureSocketSet.end()) { - delete *it; - m_secureSocketSet.erase(it); - } -} diff --git a/src/lib/net/SecureListenSocket.h b/src/lib/net/SecureListenSocket.h index ff19602c..960a8a26 100644 --- a/src/lib/net/SecureListenSocket.h +++ b/src/lib/net/SecureListenSocket.h @@ -33,7 +33,6 @@ public: // IListenSocket overrides virtual IDataSocket* accept(); - void deleteSocket(void*); private: typedef std::set SecureSocketSet; diff --git a/src/lib/net/TCPListenSocket.h b/src/lib/net/TCPListenSocket.h index cf4469a0..41308622 100644 --- a/src/lib/net/TCPListenSocket.h +++ b/src/lib/net/TCPListenSocket.h @@ -43,7 +43,6 @@ public: // IListenSocket overrides virtual IDataSocket* accept(); - virtual void deleteSocket(void*) { } protected: void setListeningJob(); diff --git a/src/lib/platform/CMakeLists.txt b/src/lib/platform/CMakeLists.txt index 6c272c21..481d8ef9 100644 --- a/src/lib/platform/CMakeLists.txt +++ b/src/lib/platform/CMakeLists.txt @@ -19,7 +19,7 @@ if (WIN32) file(GLOB sources "MSWindows*.cpp") elseif (APPLE) file(GLOB headers "OSX*.h" "IOSX*.h") - file(GLOB sources "OSX*.cpp" "IOSX*.cpp" "OSX*.m") + file(GLOB sources "OSX*.cpp" "IOSX*.cpp" "OSX*.m" "OSX*.mm") elseif (UNIX) file(GLOB headers "XWindows*.h") file(GLOB sources "XWindows*.cpp") diff --git a/src/lib/platform/OSXClipboard.cpp b/src/lib/platform/OSXClipboard.cpp index 84f7c7ce..7dae2081 100644 --- a/src/lib/platform/OSXClipboard.cpp +++ b/src/lib/platform/OSXClipboard.cpp @@ -122,7 +122,7 @@ OSXClipboard::add(EFormat format, const String & data) PasteboardPutItemFlavor( m_pboard, - (PasteboardItemID) 0, + nullptr, flavorType, dataRef, kPasteboardFlavorNoFlags); diff --git a/src/lib/platform/OSXScreen.h b/src/lib/platform/OSXScreen.h index dce5ac08..0357583e 100644 --- a/src/lib/platform/OSXScreen.h +++ b/src/lib/platform/OSXScreen.h @@ -344,4 +344,6 @@ private: Mutex* m_carbonLoopMutex; CondVar* m_carbonLoopReady; #endif + + class OSXScreenImpl* m_impl; }; diff --git a/src/lib/platform/OSXScreen.cpp b/src/lib/platform/OSXScreen.mm similarity index 99% rename from src/lib/platform/OSXScreen.cpp rename to src/lib/platform/OSXScreen.mm index e81f1621..2c2e66d6 100644 --- a/src/lib/platform/OSXScreen.cpp +++ b/src/lib/platform/OSXScreen.mm @@ -45,6 +45,8 @@ #include #include +#import + // Set some enums for fast user switching if we're building with an SDK // from before such support was added. #if !defined(MAC_OS_X_VERSION_10_3) || \ @@ -112,7 +114,8 @@ OSXScreen::OSXScreen(IEventQueue* events, bool isPrimary, bool autoShowHideCurso m_lastSingleClickYCursor(0), m_autoShowHideCursor(autoShowHideCursor), m_events(events), - m_getDropTargetThread(NULL) + m_getDropTargetThread(NULL), + m_impl(NULL) { try { m_displayID = CGMainDisplayID(); @@ -526,9 +529,7 @@ OSXScreen::fakeMouseButton(ButtonID id, bool press) // we define our own defaults. const double maxDiff = sqrt(2) + 0.0001; - - NXEventHandle handle = NXOpenEventStatus(); - double clickTime = NXClickTime(handle); + double clickTime = [NSEvent doubleClickInterval]; // As long as the click is within the time window and distance window // increase clickState (double click, triple click, etc) diff --git a/src/lib/server/CMakeLists.txt b/src/lib/server/CMakeLists.txt index 2c34af07..3cb582ec 100644 --- a/src/lib/server/CMakeLists.txt +++ b/src/lib/server/CMakeLists.txt @@ -35,6 +35,8 @@ endif() add_library(server STATIC ${sources}) +target_link_libraries(server shared) + if (UNIX) target_link_libraries(server synergy) endif() diff --git a/src/lib/server/ClientListener.cpp b/src/lib/server/ClientListener.cpp index 619ba2a0..a8bef7cf 100644 --- a/src/lib/server/ClientListener.cpp +++ b/src/lib/server/ClientListener.cpp @@ -106,12 +106,6 @@ ClientListener::setServer(Server* server) m_server = server; } -void -ClientListener::deleteSocket(void* socket) -{ - m_listen->deleteSocket(socket); -} - ClientProxy* ClientListener::getNextClient() { @@ -213,10 +207,6 @@ ClientListener::handleUnknownClient(const Event&, void* vclient) } delete unknownClient; - - if (m_useSecureNetwork && !handshakeOk) { - deleteSocket(socket); - } } void diff --git a/src/lib/server/ClientListener.h b/src/lib/server/ClientListener.h index 7674386c..545e163a 100644 --- a/src/lib/server/ClientListener.h +++ b/src/lib/server/ClientListener.h @@ -48,8 +48,6 @@ public: //@} - void deleteSocket(void* socket); - //! @name accessors //@{ diff --git a/src/lib/server/Server.cpp b/src/lib/server/Server.cpp index d9394ed5..ec730bcd 100644 --- a/src/lib/server/Server.cpp +++ b/src/lib/server/Server.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2002 Chris Schoeneman - * + * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE that should have accompanied this file. - * + * * This package 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 @@ -45,11 +45,13 @@ #include "base/Log.h" #include "base/TMethodEventJob.h" #include "common/stdexcept.h" +#include "shared/SerialKey.h" #include #include #include #include +#include // // Server @@ -60,7 +62,7 @@ Server::Server( PrimaryClient* primaryClient, synergy::Screen* screen, IEventQueue* events, - bool enableDragDrop) : + ServerArgs const& args) : m_mock(false), m_primaryClient(primaryClient), m_active(primaryClient), @@ -91,10 +93,10 @@ Server::Server( m_sendFileThread(NULL), m_writeToDropDirThread(NULL), m_ignoreFileTransfer(false), - m_enableDragDrop(enableDragDrop), m_enableClipboard(true), m_sendDragInfoThread(NULL), - m_waitDragInfoThread(true) + m_waitDragInfoThread(true), + m_args(args) { // must have a primary client and it must have a canonical name assert(m_primaryClient != NULL); @@ -184,7 +186,7 @@ Server::Server( new TMethodEventJob(this, &Server::handleFakeInputEndEvent)); - if (m_enableDragDrop) { + if (m_args.m_enableDragDrop) { m_events->adoptHandler(m_events->forFile().fileChunkSending(), this, new TMethodEventJob(this, @@ -451,6 +453,13 @@ Server::switchScreen(BaseClientProxy* dst, SInt32 x, SInt32 y, bool forScreensaver) { assert(dst != NULL); + + // if trial is expired, exit the process + if (m_args.m_serial.isExpired(std::time(0))) { + LOG((CLOG_ERR "trial has expired, aborting server")); + exit(kExitSuccess); + } + #ifndef NDEBUG { SInt32 dx, dy, dw, dh; @@ -534,7 +543,7 @@ Server::jumpToScreen(BaseClientProxy* newScreen) // get the last cursor position on the target screen SInt32 x, y; newScreen->getJumpCursorPos(x, y); - + switchScreen(newScreen, x, y, false); } @@ -884,14 +893,14 @@ Server::isSwitchOkay(BaseClientProxy* newScreen, if (!preventSwitch && ( (this->m_switchNeedsShift && ((mods & KeyModifierShift) != KeyModifierShift)) || - (this->m_switchNeedsControl && ((mods & KeyModifierControl) != KeyModifierControl)) || + (this->m_switchNeedsControl && ((mods & KeyModifierControl) != KeyModifierControl)) || (this->m_switchNeedsAlt && ((mods & KeyModifierAlt) != KeyModifierAlt)) )) { LOG((CLOG_DEBUG1 "need modifiers to switch")); preventSwitch = true; stopSwitch(); - } - + } + return !preventSwitch; } @@ -1171,7 +1180,7 @@ Server::processOptions() } else if (id == kOptionClipboardSharing) { m_enableClipboard = (value != 0); - + if (m_enableClipboard == false) { LOG((CLOG_NOTE "clipboard sharing is disabled")); } @@ -1378,10 +1387,7 @@ Server::handleClientDisconnected(const Event&, void* vclient) removeActiveClient(client); removeOldClient(client); - PacketStreamFilter* streamFileter = dynamic_cast(client->getStream()); - TCPSocket* socket = dynamic_cast(streamFileter->getStream()); delete client; - m_clientListener->deleteSocket(socket); } void @@ -1391,16 +1397,14 @@ Server::handleClientCloseTimeout(const Event&, void* vclient) BaseClientProxy* client = static_cast(vclient); LOG((CLOG_NOTE "forced disconnection of client \"%s\"", getName(client).c_str())); removeOldClient(client); - PacketStreamFilter* streamFileter = dynamic_cast(client->getStream()); - TCPSocket* socket = dynamic_cast(streamFileter->getStream()); + delete client; - m_clientListener->deleteSocket(socket); } void Server::handleSwitchToScreenEvent(const Event& event, void*) { - SwitchToScreenInfo* info = + SwitchToScreenInfo* info = static_cast(event.getData()); ClientList::const_iterator index = m_clients.find(info->m_screen); @@ -1415,7 +1419,7 @@ Server::handleSwitchToScreenEvent(const Event& event, void*) void Server::handleSwitchInDirectionEvent(const Event& event, void*) { - SwitchInDirectionInfo* info = + SwitchInDirectionInfo* info = static_cast(event.getData()); // jump to screen in chosen direction from center of this screen @@ -1705,8 +1709,8 @@ Server::onMouseUp(ButtonID id) m_ignoreFileTransfer = false; return; } - - if (m_enableDragDrop) { + + if (m_args.m_enableDragDrop) { if (!m_screen->isOnScreen()) { String& file = m_screen->getDraggingFilename(); if (!file.empty()) { @@ -1791,7 +1795,7 @@ Server::onMouseMovePrimary(SInt32 x, SInt32 y) // should we switch or not? if (isSwitchOkay(newScreen, dir, x, y, xc, yc)) { - if (m_enableDragDrop + if (m_args.m_enableDragDrop && m_screen->isDraggingStarted() && m_active != newScreen && m_waitDragInfoThread) { @@ -1810,7 +1814,7 @@ Server::onMouseMovePrimary(SInt32 x, SInt32 y) m_waitDragInfoThread = true; return true; } - + return false; } @@ -1826,7 +1830,7 @@ Server::sendDragInfoThread(void* arg) di.setFilename(dragFileList); m_dragFileList.push_back(di); } - + #if defined(__APPLE__) // on mac it seems that after faking a LMB up, system would signal back // to synergy a mouse up event, which doesn't happen on windows. as a @@ -1849,7 +1853,7 @@ Server::sendDragInfo(BaseClientProxy* newScreen) { String infoString; UInt32 fileCount = DragInformation::setupDragInfo(m_dragFileList, infoString); - + if (fileCount > 0) { char* info = NULL; size_t size = infoString.size(); @@ -2059,7 +2063,7 @@ Server::onFileChunkSending(const void* data) assert(m_active != NULL); // relay - m_active->fileChunkSending(chunk->m_chunk[0], &chunk->m_chunk[1], chunk->m_dataSize); + m_active->fileChunkSending(chunk->m_chunk[0], &chunk->m_chunk[1], chunk->m_dataSize); } void @@ -2368,7 +2372,7 @@ Server::sendFileToClient(const char* filename) if (m_sendFileThread != NULL) { StreamChunker::interruptFile(); } - + m_sendFileThread = new Thread( new TMethodJob( this, &Server::sendFileThread, @@ -2393,7 +2397,7 @@ Server::sendFileThread(void* data) void Server::dragInfoReceived(UInt32 fileNum, String content) { - if (!m_enableDragDrop) { + if (!m_args.m_enableDragDrop) { LOG((CLOG_DEBUG "drag drop not enabled, ignoring drag info.")); return; } diff --git a/src/lib/server/Server.h b/src/lib/server/Server.h index 7681487a..d1e48bd5 100644 --- a/src/lib/server/Server.h +++ b/src/lib/server/Server.h @@ -25,6 +25,7 @@ #include "synergy/mouse_types.h" #include "synergy/INode.h" #include "synergy/DragInformation.h" +#include "synergy/ServerArgs.h" #include "base/Event.h" #include "base/Stopwatch.h" #include "base/EventTypes.h" @@ -106,7 +107,7 @@ public: ownership of \p primaryClient. */ Server(Config& config, PrimaryClient* primaryClient, - synergy::Screen* screen, IEventQueue* events, bool enableDragDrop); + synergy::Screen* screen, IEventQueue* events, ServerArgs const& args); ~Server(); #ifdef TEST_ENV @@ -472,11 +473,11 @@ private: Thread* m_writeToDropDirThread; String m_dragFileExt; bool m_ignoreFileTransfer; - bool m_enableDragDrop; bool m_enableClipboard; Thread* m_sendDragInfoThread; bool m_waitDragInfoThread; ClientListener* m_clientListener; + ServerArgs m_args; }; diff --git a/src/lib/shared/CMakeLists.txt b/src/lib/shared/CMakeLists.txt new file mode 100644 index 00000000..891f4aa7 --- /dev/null +++ b/src/lib/shared/CMakeLists.txt @@ -0,0 +1,32 @@ +# synergy -- mouse and keyboard sharing utility +# Copyright (C) 2016 Symless Ltd. +# +# This package is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# found in the file LICENSE that should have accompanied this file. +# +# This package 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 this program. If not, see . + +file(GLOB headers "*.h") +file(GLOB sources "*.cpp") + +if (SYNERGY_ADD_HEADERS) + list(APPEND sources ${headers}) +endif() + +add_library(shared STATIC ${sources}) + +include_directories( + ../ + ../../../ext + ../../../ext/gtest-1.6.0/include +) + +target_link_libraries(shared arch base) + diff --git a/src/gui/src/EditionType.h b/src/lib/shared/EditionType.h similarity index 90% rename from src/gui/src/EditionType.h rename to src/lib/shared/EditionType.h index 5869a32b..66f30aa9 100644 --- a/src/gui/src/EditionType.h +++ b/src/lib/shared/EditionType.h @@ -20,11 +20,11 @@ /* Do not reorder these! */ -enum EditionType { - Basic, - Pro, - Trial, - Unregistered +enum Edition { + kBasic, + kPro, + Trial_DO_NOT_USE_OR_THERE_WILL_BE_PAIN, + kUnregistered }; #endif // EDITIONTYPE_H diff --git a/src/lib/shared/SerialKey.cpp b/src/lib/shared/SerialKey.cpp new file mode 100644 index 00000000..60a039cb --- /dev/null +++ b/src/lib/shared/SerialKey.cpp @@ -0,0 +1,264 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package 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 this program. If not, see . + */ + +#include "SerialKey.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +SerialKey::SerialKey(Edition edition): + m_userLimit(1), + m_warnTime(ULLONG_MAX), + m_expireTime(ULLONG_MAX), + m_edition(edition), + m_trial(false) +{ +} + +SerialKey::SerialKey(std::string serial) : + m_userLimit(1), + m_warnTime(0), + m_expireTime(0), + m_edition(kBasic), + m_trial(true) +{ + string plainText = decode(serial); + bool valid = false; + if (!plainText.empty()) { + valid = parse(plainText); + } + if (!valid) { + throw std::runtime_error ("Invalid serial key"); + } +} + +bool +SerialKey::isExpiring(time_t currentTime) const +{ + bool result = false; + + if (m_trial) { + if (m_warnTime <= currentTime && currentTime < m_expireTime) { + result = true; + } + } + + return result; +} + +bool +SerialKey::isExpired(time_t currentTime) const +{ + bool result = false; + + if (m_trial) { + if (m_expireTime <= currentTime) { + result = true; + } + } + + return result; +} + +bool +SerialKey::isTrial() const +{ + return m_trial; +} + +Edition +SerialKey::edition() const +{ + return m_edition; +} + +std::string +SerialKey::editionString() const +{ + switch (edition()) { + case kBasic: + return "basic"; + case kPro: + return "pro"; + default: { + std::ostringstream oss; + oss << static_cast(edition()); + return oss.str(); + } + } +} + +static std::string +hexEncode (std::string const& str) { + std::ostringstream oss; + for (size_t i = 0; i < str.size(); ++i) { + int c = str[i]; + oss << std::setfill('0') << std::hex << std::setw(2) + << std::uppercase; + oss << c; + } + return oss.str(); +} + +std::string +SerialKey::toString() const +{ + std::ostringstream oss; + oss << "{"; + if (isTrial()) { + oss << "v2;trial;"; + } else { + oss << "v1;"; + } + oss << editionString() << ";"; + oss << m_name << ";"; + oss << m_userLimit << ";"; + oss << m_email << ";"; + oss << m_company << ";"; + oss << (isTrial() ? m_warnTime : 0) << ";"; + oss << (isTrial() ? m_expireTime : 0); + oss << "}"; + return hexEncode(oss.str()); +} + +time_t +SerialKey::daysLeft(time_t currentTime) const +{ + unsigned long long timeLeft = 0; + unsigned long long const day = 60 * 60 * 24; + + if (currentTime < m_expireTime) { + timeLeft = m_expireTime - currentTime; + } + + unsigned long long daysLeft = 0; + daysLeft = timeLeft % day != 0 ? 1 : 0; + + return timeLeft / day + daysLeft; +} + +std::string +SerialKey::email() const +{ + return m_email; +} + +std::string +SerialKey::decode(const std::string& serial) +{ + static const char* const lut = "0123456789ABCDEF"; + string output; + size_t len = serial.length(); + if (len & 1) { + return output; + } + + output.reserve(len / 2); + for (size_t i = 0; i < len; i += 2) { + + char a = serial[i]; + char b = serial[i + 1]; + + const char* p = std::lower_bound(lut, lut + 16, a); + const char* q = std::lower_bound(lut, lut + 16, b); + + if (*q != b || *p != a) { + return output; + } + + output.push_back(static_cast(((p - lut) << 4) | (q - lut))); + } + + return output; +} + +bool +SerialKey::parse(std::string plainSerial) +{ + string parityStart = plainSerial.substr(0, 1); + string parityEnd = plainSerial.substr(plainSerial.length() - 1, 1); + + bool valid = false; + + // check for parity chars { and }, record parity result, then remove them. + if (parityStart == "{" && parityEnd == "}") { + plainSerial = plainSerial.substr(1, plainSerial.length() - 2); + + // tokenize serialised subscription. + vector parts; + std::string::size_type pos = 0; + bool look = true; + while (look) { + std::string::size_type start = pos; + pos = plainSerial.find(";", pos); + if (pos == string::npos) { + pos = plainSerial.length(); + look = false; + } + parts.push_back(plainSerial.substr(start, pos - start)); + pos += 1; + } + + if ((parts.size() == 8) + && (parts.at(0).find("v1") != string::npos)) { + // e.g.: {v1;basic;Bob;1;email;company name;1398297600;1398384000} + m_edition = parseEdition(parts.at(1)); + m_name = parts.at(2); + m_trial = false; + sscanf(parts.at(3).c_str(), "%d", &m_userLimit); + m_email = parts.at(4); + m_company = parts.at(5); + sscanf(parts.at(6).c_str(), "%lld", &m_warnTime); + sscanf(parts.at(7).c_str(), "%lld", &m_expireTime); + valid = true; + } + else if ((parts.size() == 9) + && (parts.at(0).find("v2") != string::npos)) { + // e.g.: {v2;trial;basic;Bob;1;email;company name;1398297600;1398384000} + m_trial = parts.at(1) == "trial" ? true : false; + m_edition = parseEdition(parts.at(2)); + m_name = parts.at(3); + sscanf(parts.at(4).c_str(), "%d", &m_userLimit); + m_email = parts.at(5); + m_company = parts.at(6); + sscanf(parts.at(7).c_str(), "%lld", &m_warnTime); + sscanf(parts.at(8).c_str(), "%lld", &m_expireTime); + valid = true; + } + } + + return valid; +} + +Edition +SerialKey::parseEdition(std::string const& editionStr) +{ + Edition e = kBasic; + if (editionStr == "pro") { + e = kPro; + } + + return e; +} diff --git a/src/lib/shared/SerialKey.h b/src/lib/shared/SerialKey.h new file mode 100644 index 00000000..dd9b7160 --- /dev/null +++ b/src/lib/shared/SerialKey.h @@ -0,0 +1,84 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package 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 this program. If not, see . + */ + +#pragma once + +#include +#include +#include "EditionType.h" + +#ifdef TEST_ENV +#include "gtest/gtest_prod.h" +#endif + +class SerialKey { + friend bool operator== (SerialKey const&, SerialKey const&); +public: + explicit SerialKey(Edition edition = kUnregistered); + explicit SerialKey(std::string serial); + + bool isExpiring(time_t currentTime) const; + bool isExpired(time_t currentTime) const; + bool isTrial() const; + time_t daysLeft(time_t currentTime) const; + std::string email() const; + Edition edition() const; + std::string toString() const; + + static std::string decode(const std::string& serial); + static Edition parseEdition(const std::string& editionStr); + +private: + bool parse(std::string plainSerial); + std::string editionString() const; + +#ifdef TEST_ENV +private: + FRIEND_TEST(SerialKeyTests, parse_noParty_invalid); + FRIEND_TEST(SerialKeyTests, parse_invalidPartsLenghth_invalid); + FRIEND_TEST(SerialKeyTests, parse_validV1Serial_valid); + FRIEND_TEST(SerialKeyTests, parse_validV2Serial_valid); +#endif + +private: + std::string m_name; + std::string m_email; + std::string m_company; + unsigned m_userLimit; + unsigned long long m_warnTime; + unsigned long long m_expireTime; + Edition m_edition; + bool m_trial; +}; + + +inline bool +operator== (SerialKey const& lhs, SerialKey const& rhs) { + return (lhs.m_name == rhs.m_name) && + (lhs.m_email == rhs.m_email) && + (lhs.m_company == rhs.m_company) && + (lhs.m_userLimit == rhs.m_userLimit) && + (lhs.m_warnTime == rhs.m_warnTime) && + (lhs.m_expireTime == rhs.m_expireTime) && + (lhs.m_edition == rhs.m_edition) && + (lhs.m_trial == rhs.m_trial); +} + +inline bool +operator!= (SerialKey const& lhs, SerialKey const& rhs) { + return !(lhs == rhs); +} diff --git a/src/lib/synergy/ArgParser.cpp b/src/lib/synergy/ArgParser.cpp index 431a91b7..6693ebf0 100644 --- a/src/lib/synergy/ArgParser.cpp +++ b/src/lib/synergy/ArgParser.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. - * + * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE that should have accompanied this file. - * + * * This package 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 @@ -70,6 +70,9 @@ ArgParser::parseServerArgs(ServerArgs& args, int argc, const char* const* argv) else if (isArg(i, argc, argv, "", "--prm-hc", 1)) { DpiHelper::s_primaryHeightCenter = synergy::string::stringToSizeType(argv[++i]); } + else if (isArg(i, argc, argv, "", "--serial-key", 1)) { + args.m_serial = SerialKey(argv[++i]); + } else { LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE, args.m_pname, argv[i], args.m_pname)); return false; @@ -107,7 +110,7 @@ ArgParser::parseClientArgs(ClientArgs& args, int argc, const char* const* argv) // ignore -- included for backwards compatibility } else if (isArg(i, argc, argv, NULL, "--yscroll", 1)) { - // define scroll + // define scroll args.m_yscroll = atoi(argv[++i]); } else { @@ -189,18 +192,10 @@ ArgParser::parseToolArgs(ToolArgs& args, int argc, const char* const* argv) args.m_loginAuthenticate = true; return true; } - else if (isArg(i, argc, argv, NULL, "--get-plugin-list", 0)) { - args.m_getPluginList = true; - return true; - } else if (isArg(i, argc, argv, NULL, "--get-installed-dir", 0)) { args.m_getInstalledDir = true; return true; } - else if (isArg(i, argc, argv, NULL, "--get-plugin-dir", 0)) { - args.m_getPluginDir = true; - return true; - } else if (isArg(i, argc, argv, NULL, "--get-profile-dir", 0)) { args.m_getProfileDir = true; return true; @@ -209,26 +204,14 @@ ArgParser::parseToolArgs(ToolArgs& args, int argc, const char* const* argv) args.m_getArch = true; return true; } - else if (isArg(i, argc, argv, NULL, "--subscription-serial", 1)) { - args.m_subscriptionSerial = argv[++i]; - if (args.m_subscriptionSerial.empty()) { - LOG((CLOG_CRIT "subscription error: serial was not provided")); - return false; - } - return true; - } - else if (isArg(i, argc, argv, NULL, "--get-subscription-filename", 0)) { - args.m_getSubscriptionFilename = true; - return true; - } - else if (isArg(i, argc, argv, NULL, "--check-subscription", 0)) { - args.m_checkSubscription = true; - return true; - } else if (isArg(i, argc, argv, NULL, "--notify-activation", 0)) { args.m_notifyActivation = true; return true; } + else if (isArg(i, argc, argv, NULL, "--notify-update", 0)) { + args.m_notifyUpdate = true; + return true; + } else { return false; } @@ -292,10 +275,10 @@ ArgParser::parseGenericArgs(int argc, const char* const* argv, int& i) argsBase().m_enableIpc = true; } else if (isArg(i, argc, argv, NULL, "--server")) { - // HACK: stop error happening when using portable (synergyp) + // HACK: stop error happening when using portable (synergyp) } else if (isArg(i, argc, argv, NULL, "--client")) { - // HACK: stop error happening when using portable (synergyp) + // HACK: stop error happening when using portable (synergyp) } else if (isArg(i, argc, argv, NULL, "--enable-drag-drop")) { bool useDragDrop = true; @@ -399,7 +382,7 @@ ArgParser::splitCommandString(String& command, std::vector& argv) else if (space > rightDoubleQuote){ searchDoubleQuotes(command, leftDoubleQuote, rightDoubleQuote, rightDoubleQuote + 1); } - + if (!ignoreThisSpace) { String subString = command.substr(startPos, space - startPos); @@ -465,7 +448,7 @@ ArgParser::getArgv(std::vector& argsArray) // them to the inner array. So caller only need to use // delete[] to delete the outer array const char** argv = new const char*[argc]; - + for (size_t i = 0; i < argc; i++) { argv[i] = argsArray[i].c_str(); } @@ -497,7 +480,7 @@ ArgParser::assembleCommand(std::vector& argsArray, String ignoreArg, in if (!result.empty()) { // remove the tail space - result = result.substr(0, result.size() - 1); + result = result.substr(0, result.size() - 1); } return result; @@ -514,13 +497,13 @@ bool ArgParser::checkUnexpectedArgs() { #if SYSAPI_WIN32 - // suggest that user installs as a windows service. when launched as + // suggest that user installs as a windows service. when launched as // service, process should automatically detect that it should run in // daemon mode. if (argsBase().m_daemon) { - LOG((CLOG_ERR + LOG((CLOG_ERR "the --daemon argument is not supported on windows. " - "instead, install %s as a service (--service install)", + "instead, install %s as a service (--service install)", argsBase().m_pname)); return true; } diff --git a/src/lib/synergy/ServerApp.cpp b/src/lib/synergy/ServerApp.cpp index 23884aec..ae1a2077 100644 --- a/src/lib/synergy/ServerApp.cpp +++ b/src/lib/synergy/ServerApp.cpp @@ -647,7 +647,7 @@ ServerApp::openClientListener(const NetworkAddress& address) Server* ServerApp::openServer(Config& config, PrimaryClient* primaryClient) { - Server* server = new Server(config, primaryClient, m_serverScreen, m_events, args().m_enableDragDrop); + Server* server = new Server(config, primaryClient, m_serverScreen, m_events, args()); try { m_events->adoptHandler( m_events->forServer().disconnected(), server, diff --git a/src/lib/synergy/ServerArgs.cpp b/src/lib/synergy/ServerArgs.cpp index f56f6e8d..52166f2a 100644 --- a/src/lib/synergy/ServerArgs.cpp +++ b/src/lib/synergy/ServerArgs.cpp @@ -19,6 +19,7 @@ ServerArgs::ServerArgs() : m_configFile(), + m_serial(), m_config(NULL) { } diff --git a/src/lib/synergy/ServerArgs.h b/src/lib/synergy/ServerArgs.h index 54310f8e..e139d110 100644 --- a/src/lib/synergy/ServerArgs.h +++ b/src/lib/synergy/ServerArgs.h @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. - * + * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE that should have accompanied this file. - * + * * This package 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 @@ -18,6 +18,7 @@ #pragma once #include "synergy/ArgsBase.h" +#include "shared/SerialKey.h" class NetworkAddress; class Config; @@ -28,5 +29,6 @@ public: public: String m_configFile; + SerialKey m_serial; Config* m_config; }; diff --git a/src/lib/synergy/SubscriptionKey.h b/src/lib/synergy/SubscriptionKey.h deleted file mode 100644 index 28744fed..00000000 --- a/src/lib/synergy/SubscriptionKey.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2015 Synergy Seamless Inc. - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * found in the file LICENSE that should have accompanied this file. - * - * This package 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 this program. If not, see . - */ - -#pragma once - -#include "base/String.h" - -struct SubscriptionKey { - String m_name; - String m_type; - String m_email; - String m_company; - int m_userLimit; - int m_warnTime; - int m_expireTime; -}; diff --git a/src/lib/synergy/SubscriptionManager.cpp b/src/lib/synergy/SubscriptionManager.cpp deleted file mode 100644 index 78207dc2..00000000 --- a/src/lib/synergy/SubscriptionManager.cpp +++ /dev/null @@ -1,199 +0,0 @@ -/* - * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2015 Synergy Seamless Inc. - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * found in the file LICENSE that should have accompanied this file. - * - * This package 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 this program. If not, see . - */ - -#include "synergy/SubscriptionManager.h" - -#include "synergy/XSynergy.h" -#include "arch/Arch.h" -#include "base/Log.h" -#include "base/String.h" -#include "common/Version.h" - -#include -#include -#include -#include -#include -//#include - -#if SYSAPI_WIN32 -const char* kFile = "Synergy.subkey"; -#else -const char* kFile = ".synergy.subkey"; -#endif - -// -// SubscriptionManager -// - -SubscriptionManager::SubscriptionManager() : - m_key() -{ -} - -void -SubscriptionManager::checkFile(const String& filename_) -{ - String filename = filename_; - if (filename.empty()) { - filename = getFilename(); - } - - std::ifstream stream(filename.c_str()); - if (!stream.is_open()) { - throw XSubscription(synergy::string::sprintf( - "Could not open, path=%s", filename.c_str())); - } - - String serial; - stream >> serial; - - String plainText = decode(serial); - parsePlainSerial(plainText, m_key); - - LOG((CLOG_DEBUG "subscription is valid")); -} - -void -SubscriptionManager::activate(const String& serial) -{ - String plainText = decode(serial); - parsePlainSerial(plainText, m_key); - - String filename = getFilename(); - std::ofstream stream(filename.c_str()); - if (!stream.is_open()) { - throw XSubscription(synergy::string::sprintf( - "Could not open, file=%s", filename.c_str())); - } - - stream << serial << std::endl; - LOG((CLOG_DEBUG "subscription file created, path=%s", filename.c_str())); -} - -String -SubscriptionManager::decode(const String& input) -{ - static const char* const lut = "0123456789ABCDEF"; - size_t len = input.length(); - if (len & 1) { - throw XSubscription("Invalid serial, wrong length."); - } - - String output; - output.reserve(len / 2); - for (size_t i = 0; i < len; i += 2) { - - char a = input[i]; - char b = input[i + 1]; - - const char* p = std::lower_bound(lut, lut + 16, a); - const char* q = std::lower_bound(lut, lut + 16, b); - - if (*q != b || *p != a) { - throw XSubscription("Invalid serial, unrecognized digit."); - } - - output.push_back(static_cast(((p - lut) << 4) | (q - lut))); - } - - return output; -} - -void -SubscriptionManager::parsePlainSerial(const String& plainText, SubscriptionKey& key) -{ - String serial; - String parityStart = plainText.substr(0, 1); - String parityEnd = plainText.substr(plainText.length() - 1, 1); - - // check for parity chars { and }, record parity result, then remove them. - if (parityStart == "{" && parityEnd == "}") { - serial = plainText.substr(1, plainText.length() - 2); - - // tokenize serialised subscription. - std::vector parts; - std::string::size_type pos = 0; - bool look = true; - while (look) { - std::string::size_type start = pos; - pos = serial.find(";", pos); - if (pos == String::npos) { - pos = plainText.length(); - look = false; - } - parts.push_back(serial.substr(start, pos - start)); - pos += 1; - } - - // e.g.: {v1;trial;Bob;1;email;company name;1398297600;1398384000} - if ((parts.size() == 8) - && (parts.at(0).find("v1") != String::npos)) { - key.m_type = parts.at(1); - key.m_name = parts.at(2); - sscanf(parts.at(3).c_str(), "%d", &key.m_userLimit); - key.m_email = parts.at(4); - key.m_company = parts.at(5); - sscanf(parts.at(6).c_str(), "%d", &key.m_warnTime); - sscanf(parts.at(7).c_str(), "%d", &key.m_expireTime); - - // only limit to trial version - if (key.m_type == "trial") { - if (time(0) > key.m_expireTime) { - throw XSubscription("trial has expired"); - } - else if (time(0) > key.m_warnTime) { - int secLeft = key.m_expireTime - static_cast(time(0)); - const int spd = 60 * 60 * 24; - int dayLeft = secLeft / spd + 1; - LOG((CLOG_NOTE "trial will end in %d %s", - dayLeft, - dayLeft == 1 ? "day" : "days")); - } - } - - const char* userText = (key.m_userLimit == 1) ? "user" : "users"; - LOG((CLOG_INFO "%s subscription valid is for %d %s, registered to %s", - key.m_type.c_str(), - key.m_userLimit, - userText, - key.m_name.c_str())); - - return; - } - } - - throw XSubscription(synergy::string::sprintf("Serial is invalid.")); -} - -String -SubscriptionManager::getFilename() -{ - String path = ARCH->getProfileDirectory(); - path = ARCH->concatPath(path, kFile); - if (path.empty()) { - throw XSubscription("Could not get filename."); - } - - return path; -} - -void -SubscriptionManager::printFilename() -{ - std::cout << getFilename() << std::endl; -} diff --git a/src/lib/synergy/SubscriptionManager.h b/src/lib/synergy/SubscriptionManager.h deleted file mode 100644 index fb52701b..00000000 --- a/src/lib/synergy/SubscriptionManager.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2015 Synergy Seamless Inc. - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * found in the file LICENSE that should have accompanied this file. - * - * This package 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 this program. If not, see . - */ - -#pragma once - -#include "SubscriptionKey.h" -#include "common/common.h" - -#include "gtest/gtest_prod.h" - -class SubscriptionManager { -public: - SubscriptionManager(); - - //! Check the subscription activation file - void checkFile(const String& filename); - - //! Create a subscription activation file based on a serial - void activate(const String& serial); - - //! Use standard output to return subscription filename to gui - void printFilename(); - -private: - FRIEND_TEST(SubscriptionTests, decode_invalidLength_throwException); - FRIEND_TEST(SubscriptionTests, decode_invalidSerial_outputPlainText); - FRIEND_TEST(SubscriptionTests, decode_unrecognizedDigit_throwException); - FRIEND_TEST(SubscriptionTests, parsePlainSerial_noParity_throwException); - FRIEND_TEST(SubscriptionTests, parsePlainSerial_invalidSerial_throwException); - FRIEND_TEST(SubscriptionTests, parsePlainSerial_validSerial_validSubscriptionKey); - FRIEND_TEST(SubscriptionTests, parsePlainSerial_expiredTrialSerial_throwException); - FRIEND_TEST(SubscriptionTests, parsePlainSerial_expiredBasicSerial_validSubscriptionKey); - FRIEND_TEST(SubscriptionTests, parsePlainSerial_validSerialWithoutCompany_validSubscriptionKey); - -private: - String decode(const String& input); - void parsePlainSerial(const String& plainText, SubscriptionKey& key); - String getFilename(); - - SubscriptionKey m_key; -}; diff --git a/src/lib/synergy/ToolApp.cpp b/src/lib/synergy/ToolApp.cpp index e6695f51..3dcfd05d 100644 --- a/src/lib/synergy/ToolApp.cpp +++ b/src/lib/synergy/ToolApp.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. - * + * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE that should have accompanied this file. - * + * * This package 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 @@ -18,7 +18,6 @@ #include "synergy/ToolApp.h" #include "synergy/ArgParser.h" -#include "synergy/SubscriptionManager.h" #include "arch/Arch.h" #include "base/Log.h" #include "base/String.h" @@ -72,50 +71,17 @@ ToolApp::run(int argc, char** argv) else if (m_args.m_loginAuthenticate) { loginAuth(); } - else if (m_args.m_getPluginList) { - getPluginList(); - } else if (m_args.m_getInstalledDir) { std::cout << ARCH->getInstalledDirectory() << std::endl; } - else if (m_args.m_getPluginDir) { - std::cout << ARCH->getPluginDirectory() << std::endl; - } else if (m_args.m_getProfileDir) { std::cout << ARCH->getProfileDirectory() << std::endl; } else if (m_args.m_getArch) { std::cout << ARCH->getPlatformName() << std::endl; } - else if (!m_args.m_subscriptionSerial.empty()) { - try { - SubscriptionManager subscriptionManager; - subscriptionManager.activate(m_args.m_subscriptionSerial); - } - catch (XSubscription& e) { - LOG((CLOG_CRIT "subscription error: %s", e.what())); - return kExitSubscription; - } - } - else if (m_args.m_getSubscriptionFilename) { - try { - SubscriptionManager subscriptionManager; - subscriptionManager.printFilename(); - } - catch (XSubscription& e) { - LOG((CLOG_CRIT "subscription error: %s", e.what())); - return kExitSubscription; - } - } - else if (m_args.m_checkSubscription) { - try { - SubscriptionManager subscriptionManager; - subscriptionManager.checkFile(""); - } - catch (XSubscription& e) { - LOG((CLOG_CRIT "subscription error: %s", e.what())); - return kExitSubscription; - } + else if (m_args.m_notifyUpdate) { + notifyUpdate(); } else if (m_args.m_notifyActivation) { notifyActivation(); @@ -172,11 +138,29 @@ ToolApp::loginAuth() } void -ToolApp::getPluginList() +ToolApp::notifyUpdate() { + String data; + std::cin >> data; + + std::vector parts = synergy::string::splitString(data, ':'); + size_t count = parts.size(); + + if (count == 3) { + std::stringstream ss; + ss << JSON_URL << "notify/update"; + ss << "?from=" << parts[0]; + ss << "&to=" << parts[1]; + ss << "&serial=" << parts[2]; + + std::cout << ARCH->internet().get(ss.str()) << std::endl; + } + else { + throw XSynergy("Invalid update data."); + } } -void +void ToolApp::notifyActivation() { String info; diff --git a/src/lib/synergy/ToolApp.h b/src/lib/synergy/ToolApp.h index 8706c79a..771b298f 100644 --- a/src/lib/synergy/ToolApp.h +++ b/src/lib/synergy/ToolApp.h @@ -29,8 +29,8 @@ public: private: void loginAuth(); - void getPluginList(); void notifyActivation(); + void notifyUpdate(); private: ToolArgs m_args; diff --git a/src/lib/synergy/ToolArgs.cpp b/src/lib/synergy/ToolArgs.cpp index f5d2524a..2685c1df 100644 --- a/src/lib/synergy/ToolArgs.cpp +++ b/src/lib/synergy/ToolArgs.cpp @@ -20,14 +20,10 @@ ToolArgs::ToolArgs() : m_printActiveDesktopName(false), m_loginAuthenticate(false), - m_getPluginList(false), - m_getPluginDir(false), m_getInstalledDir(false), m_getProfileDir(false), m_getArch(false), - m_getSubscriptionFilename(false), - m_checkSubscription(false), m_notifyActivation(false), - m_subscriptionSerial() + m_notifyUpdate(false) { } diff --git a/src/lib/synergy/ToolArgs.h b/src/lib/synergy/ToolArgs.h index 0ebc0a4a..4619efc1 100644 --- a/src/lib/synergy/ToolArgs.h +++ b/src/lib/synergy/ToolArgs.h @@ -26,13 +26,9 @@ public: public: bool m_printActiveDesktopName; bool m_loginAuthenticate; - bool m_getPluginList; - bool m_getPluginDir; bool m_getInstalledDir; bool m_getProfileDir; bool m_getArch; - bool m_getSubscriptionFilename; - bool m_checkSubscription; bool m_notifyActivation; - String m_subscriptionSerial; + bool m_notifyUpdate; }; diff --git a/src/test/integtests/net/NetworkTests.cpp b/src/test/integtests/net/NetworkTests.cpp index 79ef7c99..dbb3dd1e 100644 --- a/src/test/integtests/net/NetworkTests.cpp +++ b/src/test/integtests/net/NetworkTests.cpp @@ -129,7 +129,9 @@ TEST_F(NetworkTests, sendToClient_mockData) ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true)); ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter)); - Server server(serverConfig, &primaryClient, &serverScreen, &m_events, true); + ServerArgs serverArgs; + serverArgs.m_enableDragDrop = true; + Server server(serverConfig, &primaryClient, &serverScreen, &m_events, serverArgs); server.m_mock = true; listener.setServer(&server); @@ -142,10 +144,10 @@ TEST_F(NetworkTests, sendToClient_mockData) ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); - ClientArgs args; - args.m_enableDragDrop = true; - args.m_enableCrypto = false; - Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, args); + ClientArgs clientArgs; + clientArgs.m_enableDragDrop = true; + clientArgs.m_enableCrypto = false; + Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, clientArgs); m_events.adoptHandler( m_events.forFile().fileRecieveCompleted(), &client, @@ -185,7 +187,9 @@ TEST_F(NetworkTests, sendToClient_mockFile) ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true)); ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter)); - Server server(serverConfig, &primaryClient, &serverScreen, &m_events, true); + ServerArgs serverArgs; + serverArgs.m_enableDragDrop = true; + Server server(serverConfig, &primaryClient, &serverScreen, &m_events, serverArgs); server.m_mock = true; listener.setServer(&server); @@ -198,10 +202,10 @@ TEST_F(NetworkTests, sendToClient_mockFile) ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); - ClientArgs args; - args.m_enableDragDrop = true; - args.m_enableCrypto = false; - Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, args); + ClientArgs clientArgs; + clientArgs.m_enableDragDrop = true; + clientArgs.m_enableCrypto = false; + Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, clientArgs); m_events.adoptHandler( m_events.forFile().fileRecieveCompleted(), &client, @@ -235,7 +239,9 @@ TEST_F(NetworkTests, sendToServer_mockData) ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true)); ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter)); - Server server(serverConfig, &primaryClient, &serverScreen, &m_events, true); + ServerArgs serverArgs; + serverArgs.m_enableDragDrop = true; + Server server(serverConfig, &primaryClient, &serverScreen, &m_events, serverArgs); server.m_mock = true; listener.setServer(&server); @@ -247,10 +253,10 @@ TEST_F(NetworkTests, sendToServer_mockData) ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape)); ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); - ClientArgs args; - args.m_enableDragDrop = true; - args.m_enableCrypto = false; - Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, args); + ClientArgs clientArgs; + clientArgs.m_enableDragDrop = true; + clientArgs.m_enableCrypto = false; + Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, clientArgs); m_events.adoptHandler( m_events.forClientListener().connected(), &listener, @@ -290,7 +296,9 @@ TEST_F(NetworkTests, sendToServer_mockFile) ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true)); ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter)); - Server server(serverConfig, &primaryClient, &serverScreen, &m_events, true); + ServerArgs serverArgs; + serverArgs.m_enableDragDrop = true; + Server server(serverConfig, &primaryClient, &serverScreen, &m_events, serverArgs); server.m_mock = true; listener.setServer(&server); @@ -302,10 +310,10 @@ TEST_F(NetworkTests, sendToServer_mockFile) ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape)); ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); - ClientArgs args; - args.m_enableDragDrop = true; - args.m_enableCrypto = false; - Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, args); + ClientArgs clientArgs; + clientArgs.m_enableDragDrop = true; + clientArgs.m_enableCrypto = false; + Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, clientArgs); m_events.adoptHandler( m_events.forClientListener().connected(), &listener, diff --git a/src/test/unittests/CMakeLists.txt b/src/test/unittests/CMakeLists.txt index 4cdab9bf..3e49dc3c 100644 --- a/src/test/unittests/CMakeLists.txt +++ b/src/test/unittests/CMakeLists.txt @@ -68,4 +68,4 @@ endif() add_executable(unittests ${sources}) target_link_libraries(unittests - arch base client server common io net platform server synergy mt ipc gtest gmock ${libs} ${OPENSSL_LIBS}) + arch base client server common io net platform server synergy mt ipc gtest gmock shared ${libs} ${OPENSSL_LIBS}) diff --git a/src/test/unittests/shared/SerialKeyTests.cpp b/src/test/unittests/shared/SerialKeyTests.cpp new file mode 100644 index 00000000..126d26e8 --- /dev/null +++ b/src/test/unittests/shared/SerialKeyTests.cpp @@ -0,0 +1,147 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2016 Symless Inc. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package 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 this program. If not, see . + */ + +#define TEST_ENV + +#include "shared/SerialKey.h" + +#include "test/global/gtest.h" + +TEST(SerialKeyTests, decode_empty_returnEmptyString) +{ + std::string plainText = SerialKey::decode(""); + EXPECT_EQ(0, plainText.size()); +} + +TEST(SerialKeyTests, decode_invalidDigit_returnEmptyString) +{ + std::string plainText = SerialKey::decode("MOCKZ"); + EXPECT_EQ(0, plainText.size()); +} + +TEST(SerialKeyTests, decode_validSerial_returnPlainText) +{ + std::string plainText = SerialKey::decode("53796E6572677920726F636B7321"); + EXPECT_EQ("Synergy rocks!", plainText); +} + +TEST(SerialKeyTests, parse_noParty_invalid) +{ + SerialKey serial; + bool r = serial.parse("MOCK"); + EXPECT_FALSE(r); +} + +TEST(SerialKeyTests, parse_invalidPartsLenghth_invalid) +{ + SerialKey serial; + bool r = serial.parse("{Synergy;Rocks}"); + EXPECT_FALSE(r); +} + +TEST(SerialKeyTests, parse_validV1Serial_valid) +{ + SerialKey serial; + bool r = serial.parse("{v1;basic;Bob;1;email;company name;0;86400}"); + EXPECT_EQ(true, r); + EXPECT_EQ(kBasic, serial.edition()); + EXPECT_FALSE(serial.isExpired(0)); + EXPECT_EQ(true, serial.daysLeft(0)); + EXPECT_FALSE(serial.isExpiring(1)); +} + +TEST(SerialKeyTests, parse_validV2Serial_valid) +{ + SerialKey serial; + bool r = serial.parse("{v2;trial;pro;Bob;1;email;company name;0;86400}"); + EXPECT_EQ(true, r); + EXPECT_EQ(kPro, serial.edition()); + EXPECT_FALSE(serial.isExpired(0)); + EXPECT_EQ(true, serial.daysLeft(0)); + EXPECT_EQ(true, serial.isExpiring(1)); + EXPECT_EQ(true, serial.isTrial()); +} + +TEST(SerialKeyTests, isExpiring_validV2TrialBasicSerial_returnFalse) +{ + // {v2;trial;basic;Bob;1;email;company name;1;86400} + SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B313B38363430307D"); + EXPECT_EQ(true, serial.isTrial()); + EXPECT_FALSE(serial.isExpiring(0)); + EXPECT_EQ(kBasic, serial.edition()); +} + +TEST(SerialKeyTests, isExpiring_expiringV2TrialBasicSerial_returnTrue) +{ + // {v2;trial;basic;Bob;1;email;company name;0;86400} + SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); + EXPECT_EQ(true, serial.isTrial()); + EXPECT_EQ(true, serial.isExpiring(1)); +} + +TEST(SerialKeyTests, isExpiring_expiredV2TrialBasicSerial_returnFalse) +{ + // {v2;trial;basic;Bob;1;email;company name;0;86400} + SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); + EXPECT_EQ(true, serial.isTrial()); + EXPECT_FALSE(serial.isExpiring(86401)); +} + +TEST(SerialKeyTests, isExpired_validV2TrialBasicSerial_returnFalse) +{ + // {v2;trial;basic;Bob;1;email;company name;0;86400} + SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); + EXPECT_EQ(true, serial.isTrial()); + EXPECT_FALSE(serial.isExpired(0)); +} + +TEST(SerialKeyTests, isExpired_expiringV2TrialBasicSerial_returnFalse) +{ + // {v2;trial;basic;Bob;1;email;company name;0;86400} + SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); + EXPECT_EQ(true, serial.isTrial()); + EXPECT_FALSE(serial.isExpired(1)); +} + +TEST(SerialKeyTests, isExpired_expiredV2TrialBasicSerial_returnTrue) +{ + // {v2;trial;basic;Bob;1;email;company name;0;86400} + SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); + EXPECT_EQ(true, serial.isTrial()); + EXPECT_EQ(true, serial.isExpired(86401)); +} + +TEST(SerialKeyTests, daysLeft_validExactlyOneDayV2TrialBasicSerial_returnOne) +{ + // {v2;trial;basic;Bob;1;email;company name;0;86400} + SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); + EXPECT_EQ(1, serial.daysLeft(0)); +} + +TEST(SerialKeyTests, daysLeft_validWithinOneDayV2TrialBasicSerial_returnOne) +{ + // {v2;trial;basic;Bob;1;email;company name;0;86400} + SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); + EXPECT_EQ(1, serial.daysLeft(1)); +} + +TEST(SerialKeyTests, daysLeft_expiredV2TrialBasicSerial_returnZero) +{ + // {v2;trial;basic;Bob;1;email;company name;0;86400} + SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); + EXPECT_EQ(0, serial.daysLeft(86401)); +} diff --git a/src/test/unittests/synergy/ServerArgsParsingTests.cpp b/src/test/unittests/synergy/ServerArgsParsingTests.cpp index 5ae18b94..f931f7e5 100644 --- a/src/test/unittests/synergy/ServerArgsParsingTests.cpp +++ b/src/test/unittests/synergy/ServerArgsParsingTests.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. - * + * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE that should have accompanied this file. - * + * * This package 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 diff --git a/src/test/unittests/synergy/SubscriptionTests.cpp b/src/test/unittests/synergy/SubscriptionTests.cpp deleted file mode 100644 index eeda3e7b..00000000 --- a/src/test/unittests/synergy/SubscriptionTests.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* - * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2015 Synergy Seamless Inc. - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * found in the file LICENSE that should have accompanied this file. - * - * This package 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 this program. If not, see . - */ - -#include "synergy/SubscriptionManager.h" -#include "synergy/XSynergy.h" - -#include "test/global/gtest.h" - -TEST(SubscriptionTests, decode_invalidLength_throwException) -{ - SubscriptionManager subscriptionManager; - String serial("ABC"); - - EXPECT_THROW(subscriptionManager.decode(serial), XSubscription); -} - -TEST(SubscriptionTests, decode_unrecognizedDigit_throwException) -{ - SubscriptionManager subscriptionManager; - String serial("MOCK"); - - EXPECT_THROW(subscriptionManager.decode(serial), XSubscription); -} - -TEST(SubscriptionTests, parsePlainSerial_noParity_throwException) -{ - SubscriptionManager subscriptionManager; - String painText("MOCK"); - SubscriptionKey key; - - EXPECT_THROW(subscriptionManager.parsePlainSerial(painText, key), XSubscription); -} - -TEST(SubscriptionTests, parsePlainSerial_invalidSerial_throwException) -{ - SubscriptionManager subscriptionManager; - String painText("{MOCK}"); - SubscriptionKey key; - - EXPECT_THROW(subscriptionManager.parsePlainSerial(painText, key), XSubscription); -} - -TEST(SubscriptionTests, parsePlainSerial_validSerial_validSubscriptionKey) -{ - // valid until 2 March 2049 - SubscriptionManager subscriptionManager; - String painText("{v1;trial;Bob;1;a@a.a;mock company;2147483647;2147483647}"); - SubscriptionKey key; - subscriptionManager.parsePlainSerial(painText, key); - - EXPECT_EQ("trial", key.m_type); - EXPECT_EQ("Bob", key.m_name); - EXPECT_EQ(1, key.m_userLimit); - EXPECT_EQ("a@a.a", key.m_email); - EXPECT_EQ("mock company", key.m_company); - EXPECT_EQ(2147483647, key.m_warnTime); - EXPECT_EQ(2147483647, key.m_expireTime); -} - -TEST(SubscriptionTests, parsePlainSerial_validSerialWithoutCompany_validSubscriptionKey) -{ - // valid until 2 March 2049 - SubscriptionManager subscriptionManager; - String painText("{v1;trial;Bob;1;a@a.a;;2147483647;2147483647}"); - SubscriptionKey key; - subscriptionManager.parsePlainSerial(painText, key); - - EXPECT_EQ("trial", key.m_type); - EXPECT_EQ("Bob", key.m_name); - EXPECT_EQ(1, key.m_userLimit); - EXPECT_EQ("a@a.a", key.m_email); - EXPECT_EQ("", key.m_company); - EXPECT_EQ(2147483647, key.m_warnTime); - EXPECT_EQ(2147483647, key.m_expireTime); -} - -TEST(SubscriptionTests, parsePlainSerial_expiredTrialSerial_throwException) -{ - SubscriptionManager subscriptionManager; - String painText("{v1;trial;Bob;1;1398297600;1398384000}"); - SubscriptionKey key; - - EXPECT_THROW(subscriptionManager.parsePlainSerial(painText, key), XSubscription); -} - -TEST(SubscriptionTests, parsePlainSerial_expiredBasicSerial_validSubscriptionKey) -{ - SubscriptionManager subscriptionManager; - String painText("{v1;basic;Bob;1;a@a.a;mock company;1398297600;1398384000}"); - SubscriptionKey key; - subscriptionManager.parsePlainSerial(painText, key); - - EXPECT_EQ("basic", key.m_type); - EXPECT_EQ("Bob", key.m_name); - EXPECT_EQ(1, key.m_userLimit); - EXPECT_EQ("a@a.a", key.m_email); - EXPECT_EQ("mock company", key.m_company); - EXPECT_EQ(1398297600, key.m_warnTime); - EXPECT_EQ(1398384000, key.m_expireTime); -}