diff --git a/.github/workflows/job-build-linux-centos.yml b/.github/workflows/job-build-linux-centos.yml new file mode 100644 index 000000000..b0be12485 --- /dev/null +++ b/.github/workflows/job-build-linux-centos.yml @@ -0,0 +1,35 @@ +name: CentOS + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build-arch64: + runs-on: ubuntu-latest + container: symless/synergy-core:${{ matrix.distro }} + env: + GIT_COMMIT: ${{ github.sha }} + strategy: + matrix: + include: +# - distro: centos7.6 #Need to install git 2.18+ + - distro: centos8 + + name: ${{ matrix.distro }} + + steps: + - uses: actions/checkout@v2 + + - name: Build + run: | + mkdir build + cd build + cmake3 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:PATH=$(pwd)/rpm/BUILDROOT/usr .. + . ./version + make -j + + - name: Run unit test + run: ./build/bin/unittests diff --git a/.github/workflows/job-build-linux-debian.yml b/.github/workflows/job-build-linux-debian.yml new file mode 100644 index 000000000..67fba327b --- /dev/null +++ b/.github/workflows/job-build-linux-debian.yml @@ -0,0 +1,35 @@ +name: Debian + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build-arch64: + runs-on: ubuntu-latest + container: symless/synergy-core:${{ matrix.distro }} + env: + GIT_COMMIT: ${{ github.sha }} + strategy: + matrix: + include: +# - distro: debian9 #Need to install git 2.18+ + - distro: debian10 + + name: ${{ matrix.distro }} + + steps: + - uses: actions/checkout@v2 + + - name: Build + run: | + mkdir build + cd build + cmake -DCMAKE_BUILD_TYPE=Release .. + . ./version + make -j + + - name: Run unit test + run: ./build/bin/unittests diff --git a/.github/workflows/job-build-linux-fedora.yml b/.github/workflows/job-build-linux-fedora.yml new file mode 100644 index 000000000..1efbabd3a --- /dev/null +++ b/.github/workflows/job-build-linux-fedora.yml @@ -0,0 +1,36 @@ +name: Fedora + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build-arch64: + runs-on: ubuntu-latest + container: symless/synergy-core:${{ matrix.distro }} + env: + GIT_COMMIT: ${{ github.sha }} + strategy: + matrix: + include: +# - distro: fedora28 #Need to install git 2.18+ + - distro: fedora29 + - distro: fedora30 + + name: ${{ matrix.distro }} + + steps: + - uses: actions/checkout@v2 + + - name: Build + run: | + mkdir build + cd build + cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:PATH=$(pwd)/rpm/BUILDROOT/usr .. + . ./version + make -j + + - name: Run unit test + run: ./build/bin/unittests diff --git a/.github/workflows/job-build-linux-ubuntu.yml b/.github/workflows/job-build-linux-ubuntu.yml new file mode 100644 index 000000000..45b5c5276 --- /dev/null +++ b/.github/workflows/job-build-linux-ubuntu.yml @@ -0,0 +1,55 @@ +name: Ubuntu + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build-arch64: + runs-on: ubuntu-latest + container: symless/synergy-core:${{ matrix.distro }} + env: + GIT_COMMIT: ${{ github.sha }} + strategy: + matrix: + include: + - distro: ubuntu20.04 + - distro: ubuntu19.10 +# - distro: ubuntu18.04 #Need to install git 2.18+ +# - distro: ubuntu16.04 #Need to install git 2.18+ + + name: ${{ matrix.distro }} + + steps: + - uses: actions/checkout@v2 + + - name: Build + run: | + mkdir build + cd build + cmake -DCMAKE_BUILD_TYPE=Release .. + . ./version + make -j + + - name: Run unit test + run: ./build/bin/unittests + + build_armhf: + runs-on: [self-hosted, armhf] + env: + GIT_COMMIT: ${{ github.sha }} + steps: + - uses: actions/checkout@v2 + + - name: Build + run: | + mkdir build + cd build + cmake -DCMAKE_BUILD_TYPE=Release .. + . ./version + make -j3 + + - name: Run unit test + run: ./build/bin/unittests \ No newline at end of file diff --git a/.github/workflows/job-build-mac.yml b/.github/workflows/job-build-mac.yml new file mode 100644 index 000000000..ee37bde76 --- /dev/null +++ b/.github/workflows/job-build-mac.yml @@ -0,0 +1,31 @@ +name: Mac + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build-arch64: + runs-on: macos-10.15 + + env: + GIT_COMMIT: ${{ github.sha }} + + steps: + - uses: actions/checkout@v2 + + - name: install qt + run: brew install qt + + - name: Build + run: | + mkdir build + cd build + cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=/usr/local/opt/qt .. + . ./version + make -j + + - name: Run unit test + run: ./build/bin/unittests diff --git a/.github/workflows/job-build-windows.yml b/.github/workflows/job-build-windows.yml new file mode 100644 index 000000000..2f138219d --- /dev/null +++ b/.github/workflows/job-build-windows.yml @@ -0,0 +1,71 @@ +name: Windows + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build-arch64: + runs-on: windows-2019 + + env: + GIT_COMMIT: ${{ github.sha }} + QT_BASE_DIR: ${{ github.workspace }}\deps\Qt + BONJOUR_BASE_DIR: ${{ github.workspace }}\deps\bonjour + QT_VERSION: 5.12.6 + QT_BASE_URL: http://qt.mirror.constant.com/ + + steps: + - uses: actions/checkout@v2 + + - name: Cache Qt + id: cache-qt + uses: actions/cache@v1 + with: + path: ${{ env.QT_BASE_DIR }} + key: ${{ runner.os }}-Qt_${{ env.QT_VERSION }} + + - name: Install Qt + if: steps.cache-qt.outputs.cache-hit != 'true' + run: | + pip install aqtinstall + python -m aqt install --outputdir $env:QT_BASE_DIR --base $env:QT_BASE_URL $env:QT_VERSION windows desktop win64_msvc2017_64 + cd $env:QT_BASE_DIR\$env:QT_VERSION\msvc2017_64 + dir + + - name: set QT path + run: echo "::set-env name=CMAKE_PREFIX_PATH::$env:QT_BASE_DIR\$env:QT_VERSION\msvc2017_64\" + + - name: Cache Bonjour + id: cache-bonjour + uses: actions/cache@v1 + with: + path: ${{ env.BONJOUR_BASE_DIR }} + key: ${{ runner.os }}-Bonjour + + - name: Install Bonjour SDK + if: steps.cache-bonjour.outputs.cache-hit != 'true' + run: | + New-Item -Force -ItemType Directory -Path ".\deps\bonjour" + $client = new-object System.Net.WebClient + $client.DownloadFile("https://binaries.symless.com/bonjour/BonjourSDK.zip",".\bonjoursdk.zip") + [System.IO.Compression.ZipFile]::ExtractToDirectory(".\bonjoursdk.zip", $env:BONJOUR_BASE_DIR) + + - name: set Bonjour path + run: echo "::set-env name=BONJOUR_SDK_HOME::$env:BONJOUR_BASE_DIR\BonjourSDK" + + - name: Add msbuild to PATH + uses: microsoft/setup-msbuild@v1.0.1 + + - name: Build + run: | + mkdir build + cd build + cmake -DCMAKE_BUILD_TYPE=Release .. + . ./version + msbuild synergy-core.sln /p:Configuration=Release + + - name: Run unit test + run: .\build\bin\Release\unittests.exe diff --git a/ChangeLog b/ChangeLog index 3e5c1a297..b0e006ccb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,12 +9,16 @@ Bug fixes: - #6342 Updated copyright year in version to use build date - #6771 Added Ubuntu 16 to CI/CD - #6804 Synergy loses edition when creating a System scope config +- #6660 + #6582 Add missing XAtom for utf-8 handling with Xorg Enhancements: - #6750 Integrate SonarCloud for static analysis and test coverage - #6792 License key expiry - #6799 Synergy "Business" edition +- #6803 Update Synergy icons +- #6800 Update behaviour when unregistered +- #6806 Move to Github Action for general PR builds and tests v1.12.0-stable =========== diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 07eaf1aea..695e313e4 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,5 +1,4 @@ -trigger: -- master +trigger: none jobs: - template: CI/job-doxygen.yml @@ -8,6 +7,9 @@ jobs: pool: vmImage: 'ubuntu-16.04' + #As apparently the trigger set to none doesn't work + condition: eq(variables['Build.Reason'], 'Manual') + strategy: matrix: ubuntu1604: @@ -91,6 +93,9 @@ jobs: pool: vmImage: $[ variables['image'] ] + #As apparently the trigger set to none doesn't work + condition: eq(variables['Build.Reason'], 'Manual') + variables: QT_PATH: '/usr/local/opt/qt/bin' @@ -113,6 +118,9 @@ jobs: pool: vmImage: $[ variables['image'] ] + #As apparently the trigger set to none doesn't work + condition: eq(variables['Build.Reason'], 'Manual') + variables: QT_VERSION: '5.12.6' QLI_OUT_DIR: '.\deps\Qt' diff --git a/dist/macos/bundle/Synergy.app/Contents/Resources/Synergy.icns b/dist/macos/bundle/Synergy.app/Contents/Resources/Synergy.icns index ae79e0224..3f53bed99 100644 Binary files a/dist/macos/bundle/Synergy.app/Contents/Resources/Synergy.icns and b/dist/macos/bundle/Synergy.app/Contents/Resources/Synergy.icns differ diff --git a/res/synergy.ico b/res/synergy.ico index 48590eb6b..b35873027 100644 Binary files a/res/synergy.ico and b/res/synergy.ico differ diff --git a/src/cmd/synergyc/synergyc.ico b/src/cmd/synergyc/synergyc.ico index 48590eb6b..9dfdd3835 100644 Binary files a/src/cmd/synergyc/synergyc.ico and b/src/cmd/synergyc/synergyc.ico differ diff --git a/src/cmd/synergys/synergys.ico b/src/cmd/synergys/synergys.ico index 48590eb6b..9dfdd3835 100644 Binary files a/src/cmd/synergys/synergys.ico and b/src/cmd/synergys/synergys.ico differ diff --git a/src/gui/res/icons/16x16/synergy-connected.png b/src/gui/res/icons/16x16/synergy-connected.png index 3aac760aa..43d34e628 100644 Binary files a/src/gui/res/icons/16x16/synergy-connected.png and b/src/gui/res/icons/16x16/synergy-connected.png differ diff --git a/src/gui/res/icons/16x16/synergy-disconnected.png b/src/gui/res/icons/16x16/synergy-disconnected.png index 12efe2d49..43d34e628 100644 Binary files a/src/gui/res/icons/16x16/synergy-disconnected.png and b/src/gui/res/icons/16x16/synergy-disconnected.png differ diff --git a/src/gui/res/icons/16x16/synergy-transfering.png b/src/gui/res/icons/16x16/synergy-transfering.png index 72fefca0a..43d34e628 100644 Binary files a/src/gui/res/icons/16x16/synergy-transfering.png and b/src/gui/res/icons/16x16/synergy-transfering.png differ diff --git a/src/gui/res/icons/256x256/synergy.ico b/src/gui/res/icons/256x256/synergy.ico index be951b12d..9dfdd3835 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/icons/64x64/synergy-dark-connected.png b/src/gui/res/icons/64x64/synergy-dark-connected.png index c0ee3ecf9..e02e133ad 100644 Binary files a/src/gui/res/icons/64x64/synergy-dark-connected.png and b/src/gui/res/icons/64x64/synergy-dark-connected.png differ diff --git a/src/gui/res/icons/64x64/synergy-dark-disconnected.png b/src/gui/res/icons/64x64/synergy-dark-disconnected.png index 02e18cc93..e02e133ad 100644 Binary files a/src/gui/res/icons/64x64/synergy-dark-disconnected.png and b/src/gui/res/icons/64x64/synergy-dark-disconnected.png differ diff --git a/src/gui/res/icons/64x64/synergy-dark-transfering.png b/src/gui/res/icons/64x64/synergy-dark-transfering.png index 5e9e84122..e02e133ad 100644 Binary files a/src/gui/res/icons/64x64/synergy-dark-transfering.png and b/src/gui/res/icons/64x64/synergy-dark-transfering.png differ diff --git a/src/gui/res/icons/64x64/synergy-light-connected.png b/src/gui/res/icons/64x64/synergy-light-connected.png index 821635375..8a31d2590 100644 Binary files a/src/gui/res/icons/64x64/synergy-light-connected.png and b/src/gui/res/icons/64x64/synergy-light-connected.png differ diff --git a/src/gui/res/icons/64x64/synergy-light-disconnected.png b/src/gui/res/icons/64x64/synergy-light-disconnected.png index 67592e4c2..8a31d2590 100644 Binary files a/src/gui/res/icons/64x64/synergy-light-disconnected.png and b/src/gui/res/icons/64x64/synergy-light-disconnected.png differ diff --git a/src/gui/res/icons/64x64/synergy-light-transfering.png b/src/gui/res/icons/64x64/synergy-light-transfering.png index aa77b59b2..8a31d2590 100644 Binary files a/src/gui/res/icons/64x64/synergy-light-transfering.png and b/src/gui/res/icons/64x64/synergy-light-transfering.png differ diff --git a/src/gui/res/mac/Synergy.icns b/src/gui/res/mac/Synergy.icns index 2410e6f6f..3f53bed99 100644 Binary files a/src/gui/res/mac/Synergy.icns and b/src/gui/res/mac/Synergy.icns differ diff --git a/src/gui/src/ActivationDialog.cpp b/src/gui/src/ActivationDialog.cpp index 9033ad709..0569449e1 100644 --- a/src/gui/src/ActivationDialog.cpp +++ b/src/gui/src/ActivationDialog.cpp @@ -30,10 +30,10 @@ ActivationDialog::ActivationDialog(QWidget* parent, AppConfig& appConfig, 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(m_LicenseManager->getLicenseNotice().toStdString().c_str())); + ui->m_pTextEditSerialKey->setText(m_appConfig->serialKey()); + ui->m_pTextEditSerialKey->setFocus(); + ui->m_pTextEditSerialKey->moveCursor(QTextCursor::End); + ui->m_trialLabel->setText(tr(m_LicenseManager->getLicenseNotice().toStdString().c_str())); } ActivationDialog::~ActivationDialog() @@ -47,7 +47,6 @@ void ActivationDialog::reject() CancelActivationDialog cancelActivationDialog(this); if (QDialog::Accepted == cancelActivationDialog.exec()) { m_LicenseManager->skipActivation(); - m_appConfig->activationHasRun(true); } else { return; } diff --git a/src/gui/src/LicenseManager.cpp b/src/gui/src/LicenseManager.cpp index 1447b91bf..ee52f9a3a 100644 --- a/src/gui/src/LicenseManager.cpp +++ b/src/gui/src/LicenseManager.cpp @@ -23,208 +23,208 @@ #include LicenseManager::LicenseManager(AppConfig* appConfig) : - m_AppConfig(appConfig), - m_serialKey(appConfig->edition()) { + m_AppConfig(appConfig), + m_serialKey(appConfig->edition()) { } std::pair LicenseManager::setSerialKey(SerialKey serialKey, bool acceptExpired) { - std::pair ret (true, ""); - time_t currentTime = ::time(0); + std::pair ret (true, ""); + time_t currentTime = ::time(0); - if (!acceptExpired && serialKey.isExpired(currentTime)) { - ret.first = false; - ret.second = "Serial key expired"; - return ret; - } + 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(QString::fromStdString - (m_serialKey.toString())); - emit serialKeyChanged(m_serialKey); + if (serialKey != m_serialKey) { + using std::swap; + swap (serialKey, m_serialKey); + m_AppConfig->setSerialKey(QString::fromStdString + (m_serialKey.toString())); + emit serialKeyChanged(m_serialKey); - emit showLicenseNotice(getLicenseNotice()); - if (m_serialKey.isExpired(currentTime)) { - emit LicenseExpired(); - } + emit showLicenseNotice(getLicenseNotice()); + if (!m_serialKey.isValid()) { + emit InvalidLicense(); + } - if (m_serialKey.edition() != serialKey.edition()) { - m_AppConfig->setEdition(m_serialKey.edition()); - emit editionChanged(m_serialKey.edition()); - } - } + if (m_serialKey.edition() != serialKey.edition()) { + m_AppConfig->setEdition(m_serialKey.edition()); + emit editionChanged(m_serialKey.edition()); + } + } - return ret; + return ret; } void LicenseManager::notifyUpdate(QString fromVersion, QString toVersion) const { - if ((fromVersion == "Unknown") - && (m_serialKey == SerialKey(kUnregistered))) { - return; - } + if ((fromVersion == "Unknown") + && (m_serialKey == SerialKey(kUnregistered))) { + return; + } - ActivationNotifier* notifier = new ActivationNotifier(); - notifier->setUpdateInfo (fromVersion, toVersion, - QString::fromStdString(m_serialKey.toString())); + 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())); + 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(); + notifier->moveToThread(thread); + thread->start(); - QMetaObject::invokeMethod(notifier, "notifyUpdate", - Qt::QueuedConnection); + QMetaObject::invokeMethod(notifier, "notifyUpdate", + Qt::QueuedConnection); } Edition LicenseManager::activeEdition() const { - return m_serialKey.edition(); + return m_serialKey.edition(); } QString LicenseManager::activeEditionName() const { - return getEditionName(activeEdition(), m_serialKey.isTrial()); + return getEditionName(activeEdition(), m_serialKey.isTrial()); } SerialKey LicenseManager::serialKey() const { - return m_serialKey; + return m_serialKey; } void LicenseManager::refresh() { - if (!m_AppConfig->serialKey().isEmpty()) { - try { - SerialKey serialKey (m_AppConfig->serialKey().toStdString()); - setSerialKey(serialKey, true); - } catch (...) { - m_AppConfig->clearSerialKey(); - } - } - if (m_serialKey.isExpired(::time(0))) { - emit LicenseExpired(); - } + if (!m_AppConfig->serialKey().isEmpty()) { + try { + SerialKey serialKey (m_AppConfig->serialKey().toStdString()); + setSerialKey(serialKey, true); + } catch (...) { + m_AppConfig->clearSerialKey(); + } + } + if (!m_serialKey.isValid()) { + emit InvalidLicense(); + } } void LicenseManager::skipActivation() const { - notifyActivation ("skip:unknown"); + notifyActivation ("skip:unknown"); } QString LicenseManager::getEditionName(Edition const edition, bool trial) { - SerialKeyEdition KeyEdition(edition); - std::string name = KeyEdition.getDisplayName(); + SerialKeyEdition KeyEdition(edition); + std::string name = KeyEdition.getDisplayName(); - if (trial) { - name += " (Trial)"; - } + if (trial) { + name += " (Trial)"; + } - return QString::fromUtf8 (name.c_str(), static_cast(name.size())); + return QString::fromUtf8 (name.c_str(), static_cast(name.size())); } void LicenseManager::notifyActivation(QString identity) const { - ActivationNotifier* notifier = new ActivationNotifier(); - notifier->setIdentity(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())); + 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(); + notifier->moveToThread(thread); + thread->start(); - QMetaObject::invokeMethod(notifier, "notify", Qt::QueuedConnection); + QMetaObject::invokeMethod(notifier, "notify", Qt::QueuedConnection); } QString LicenseManager::getLicenseNotice() const { - QString Notice; + QString Notice; - if (m_serialKey.isTemporary()){ - if (m_serialKey.isTrial()){ - Notice = getTrialNotice(); - } - else{ - Notice = getTemporaryNotice(); - } - } + if (m_serialKey.isTemporary()){ + if (m_serialKey.isTrial()){ + Notice = getTrialNotice(); + } + else{ + Notice = getTemporaryNotice(); + } + } - return Notice; + return Notice; } QString LicenseManager::getTrialNotice() const { - QString Notice; + QString Notice; - if (m_serialKey.isExpired(::time(0))){ - Notice = "

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

"; - Notice = Notice.arg(LicenseManager::getEditionName(activeEdition())); - } - else{ - Notice = "

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

"; + if (m_serialKey.isExpired(::time(0))){ + Notice = "

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

"; + Notice = Notice.arg(LicenseManager::getEditionName(activeEdition())); + } + else{ + Notice = "

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

"; - time_t daysLeft = m_serialKey.daysLeft(::time(0)); - Notice = Notice - .arg (daysLeft) - .arg (LicenseManager::getEditionName(activeEdition())) - .arg ((daysLeft == 1) ? "" : "s") - .arg ((daysLeft == 1) ? "s" : ""); - } + time_t daysLeft = m_serialKey.daysLeft(::time(0)); + Notice = Notice + .arg (daysLeft) + .arg (LicenseManager::getEditionName(activeEdition())) + .arg ((daysLeft == 1) ? "" : "s") + .arg ((daysLeft == 1) ? "s" : ""); + } - return Notice; + return Notice; } QString LicenseManager::getTemporaryNotice() const { - QString Notice; + QString Notice; - if (m_serialKey.isExpired(::time(0))) { - Notice = "

Your license has expired. " - "" - "Renew now!

"; - } - else if (m_serialKey.isExpiring(::time(0))) { - Notice = "

%1 day%2 " - "before your license expires." - "Renew now!" - "

"; + if (m_serialKey.isExpired(::time(0))) { + Notice = "

Your license has expired. " + "" + "Renew now!

"; + } + else if (m_serialKey.isExpiring(::time(0))) { + Notice = "

%1 day%2 " + "before your license expires." + "Renew now!" + "

"; - time_t daysLeft = m_serialKey.daysLeft(::time(0)); - Notice = Notice.arg (daysLeft).arg ((daysLeft == 1) ? "" : "s"); - } + time_t daysLeft = m_serialKey.daysLeft(::time(0)); + Notice = Notice.arg (daysLeft).arg ((daysLeft == 1) ? "" : "s"); + } - return Notice; + return Notice; } diff --git a/src/gui/src/LicenseManager.h b/src/gui/src/LicenseManager.h index 823354939..d0401a5a3 100644 --- a/src/gui/src/LicenseManager.h +++ b/src/gui/src/LicenseManager.h @@ -37,10 +37,10 @@ public: Edition activeEdition() const; QString activeEditionName() const; SerialKey serialKey() const; - void skipActivation() const; - void notifyUpdate(QString fromVersion, QString toVersion) const; - static QString getEditionName(Edition edition, bool trial = false); - void notifyActivation(QString identity) const; + void skipActivation() const; + void notifyUpdate(QString fromVersion, QString toVersion) const; + static QString getEditionName(Edition edition, bool trial = false); + void notifyActivation(QString identity) const; QString getLicenseNotice() const; private: @@ -50,7 +50,7 @@ private: signals: void serialKeyChanged (SerialKey) const; void editionChanged (Edition) const; - void LicenseExpired () const; + void InvalidLicense () const; void showLicenseNotice(const QString& notice) const; protected: diff --git a/src/gui/src/MainWindow.cpp b/src/gui/src/MainWindow.cpp index dee6eee77..0b4b3b531 100644 --- a/src/gui/src/MainWindow.cpp +++ b/src/gui/src/MainWindow.cpp @@ -174,8 +174,8 @@ MainWindow::MainWindow (AppConfig& appConfig, connect (m_LicenseManager, SIGNAL(showLicenseNotice(QString)), this, SLOT(showLicenseNotice(QString)), Qt::QueuedConnection); - connect (m_LicenseManager, SIGNAL(LicenseExpired()), - this, SLOT(LicenseExpired()), Qt::QueuedConnection); + connect (m_LicenseManager, SIGNAL(InvalidLicense()), + this, SLOT(InvalidLicense()), Qt::QueuedConnection); #endif connect (m_AppConfig, SIGNAL(sslToggled(bool)), @@ -569,8 +569,8 @@ void MainWindow::checkSecureSocket(const QString& line) // obviously not very secure, since this can be tricked by injecting something // into the log. however, since we don't have IPC between core and GUI... patches welcome. const int index = line.indexOf(tlsCheckString, 0, Qt::CaseInsensitive); - if (index > 0) { - secureSocket(true); + if (index > 0) { + secureSocket(true); //Get the protocol version from the line m_SecureSocketVersion = line.mid(index + strlen(tlsCheckString)); @@ -613,8 +613,7 @@ void MainWindow::startSynergy() { #ifndef SYNERGY_ENTERPRISE SerialKey serialKey = m_LicenseManager->serialKey(); - time_t currentTime = ::time(0); - if (serialKey.isExpired(currentTime)) { + if (!serialKey.isValid()) { if (QDialog::Rejected == raiseActivationDialog()) { return; } @@ -1152,7 +1151,7 @@ void MainWindow::setEdition(Edition edition) } #ifndef SYNERGY_ENTERPRISE -void MainWindow::LicenseExpired() +void MainWindow::InvalidLicense() { stopSynergy(); m_AppConfig->activationHasRun(false); @@ -1379,12 +1378,10 @@ int MainWindow::raiseActivationDialog() void MainWindow::on_windowShown() { #ifndef SYNERGY_ENTERPRISE - time_t currentTime = ::time(0); - if (!m_AppConfig->activationHasRun() - && ((m_AppConfig->edition() == kUnregistered) || - (m_LicenseManager->serialKey().isExpired(currentTime)))) { - raiseActivationDialog(); - } + if (!m_AppConfig->activationHasRun() && + !m_LicenseManager->serialKey().isValid()){ + raiseActivationDialog(); + } #endif } diff --git a/src/gui/src/MainWindow.h b/src/gui/src/MainWindow.h index 280ba22d4..c68dfb685 100644 --- a/src/gui/src/MainWindow.h +++ b/src/gui/src/MainWindow.h @@ -132,7 +132,7 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase public slots: void setEdition(Edition edition); #ifndef SYNERGY_ENTERPRISE - void LicenseExpired(); + void InvalidLicense(); void showLicenseNotice(const QString& message); #endif void appendLogRaw(const QString& text); diff --git a/src/lib/platform/XWindowsClipboard.cpp b/src/lib/platform/XWindowsClipboard.cpp index e5273e7f2..e567b482e 100644 --- a/src/lib/platform/XWindowsClipboard.cpp +++ b/src/lib/platform/XWindowsClipboard.cpp @@ -82,6 +82,8 @@ XWindowsClipboard::XWindowsClipboard(Display* display, m_converters.push_back(new XWindowsClipboardBMPConverter(m_display)); m_converters.push_back(new XWindowsClipboardUTF8Converter(m_display, "text/plain;charset=UTF-8")); + m_converters.push_back(new XWindowsClipboardUTF8Converter(m_display, + "text/plain;charset=utf-8")); m_converters.push_back(new XWindowsClipboardUTF8Converter(m_display, "UTF8_STRING")); m_converters.push_back(new XWindowsClipboardUCS2Converter(m_display, diff --git a/src/lib/shared/SerialKey.cpp b/src/lib/shared/SerialKey.cpp index 08829ba01..1db94308e 100644 --- a/src/lib/shared/SerialKey.cpp +++ b/src/lib/shared/SerialKey.cpp @@ -31,75 +31,88 @@ using namespace std; static std::string hexEncode (std::string const& str); SerialKey::SerialKey(Edition edition): - m_userLimit(1), - m_warnTime(ULLONG_MAX), - m_expireTime(ULLONG_MAX), - m_edition(edition) + m_userLimit(1), + m_warnTime(ULLONG_MAX), + m_expireTime(ULLONG_MAX), + m_edition(edition) { } SerialKey::SerialKey(std::string serial) : - m_userLimit(1), - m_warnTime(0), - m_expireTime(0), - m_edition(kBasic) + m_userLimit(1), + m_warnTime(0), + m_expireTime(0), + m_edition(kBasic) { - string plainText = decode(serial); - bool valid = false; - if (!plainText.empty()) { - valid = parse(plainText); - } - if (!valid) { - throw std::runtime_error ("Invalid serial key"); - } + 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; + bool result = false; - if (isTemporary()) { - unsigned long long currentTimeAsLL = static_cast(currentTime); - if ((m_warnTime <= currentTimeAsLL) && (currentTimeAsLL < m_expireTime)) { - result = true; - } - } + if (isTemporary()) { + unsigned long long currentTimeAsLL = static_cast(currentTime); + if ((m_warnTime <= currentTimeAsLL) && (currentTimeAsLL < m_expireTime)) { + result = true; + } + } - return result; + return result; } bool SerialKey::isExpired(time_t currentTime) const { - bool result = false; + bool result = false; - if (isTemporary()) { - unsigned long long currentTimeAsLL = static_cast(currentTime); - if (m_expireTime <= currentTimeAsLL) { - result = true; - } - } + if (isTemporary()) { + unsigned long long currentTimeAsLL = static_cast(currentTime); + if (m_expireTime <= currentTimeAsLL) { + result = true; + } + } - return result; + return result; } bool SerialKey::isTrial() const { - return m_KeyType.isTrial(); + return m_KeyType.isTrial(); } bool SerialKey::isTemporary() const { - return m_KeyType.isTemporary(); + return m_KeyType.isTemporary(); +} + +bool +SerialKey::isValid() const +{ + bool Valid = true; + + if (m_edition.getType() == kUnregistered || isExpired(::time(0))) + { + Valid = false; + } + + return Valid; } Edition SerialKey::edition() const { - return m_edition.getType(); + return m_edition.getType(); } static std::string @@ -118,134 +131,134 @@ hexEncode (std::string const& str) { std::string SerialKey::toString() const { - std::ostringstream oss; - oss << "{"; - if (isTemporary()) { - if (isTrial()){ - oss << "v2;" << SerialKeyType::TRIAL << ";"; - } - else{ - oss << "v2;" << SerialKeyType::SUBSCRIPTION << ";"; - } - } else { - oss << "v1;"; - } - oss << m_edition.getName() << ";"; - oss << m_name << ";"; - oss << m_userLimit << ";"; - oss << m_email << ";"; - oss << m_company << ";"; - oss << (isTemporary() ? m_warnTime : 0) << ";"; - oss << (isTemporary() ? m_expireTime : 0); - oss << "}"; - return hexEncode(oss.str()); + std::ostringstream oss; + oss << "{"; + if (isTemporary()) { + if (isTrial()){ + oss << "v2;" << SerialKeyType::TRIAL << ";"; + } + else{ + oss << "v2;" << SerialKeyType::SUBSCRIPTION << ";"; + } + } else { + oss << "v1;"; + } + oss << m_edition.getName() << ";"; + oss << m_name << ";"; + oss << m_userLimit << ";"; + oss << m_email << ";"; + oss << m_company << ";"; + oss << (isTemporary() ? m_warnTime : 0) << ";"; + oss << (isTemporary() ? 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; + unsigned long long timeLeft = 0; + unsigned long long const day = 60 * 60 * 24; - unsigned long long currentTimeAsLL = static_cast(currentTime); - if (currentTimeAsLL < m_expireTime) { - timeLeft = m_expireTime - currentTimeAsLL; - } + unsigned long long currentTimeAsLL = static_cast(currentTime); + if (currentTimeAsLL < m_expireTime) { + timeLeft = m_expireTime - currentTimeAsLL; + } - unsigned long long daysLeft = 0; - daysLeft = timeLeft % day != 0 ? 1 : 0; + unsigned long long daysLeft = 0; + daysLeft = timeLeft % day != 0 ? 1 : 0; - return timeLeft / day + daysLeft; + return timeLeft / day + daysLeft; } std::string SerialKey::email() const { - return m_email; + 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; - } + 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) { + output.reserve(len / 2); + for (size_t i = 0; i < len; i += 2) { - char a = serial[i]; - char b = serial[i + 1]; + 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); + 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; - } + if (*q != b || *p != a) { + return output; + } - output.push_back(static_cast(((p - lut) << 4) | (q - lut))); - } + output.push_back(static_cast(((p - lut) << 4) | (q - lut))); + } - return output; + return output; } bool SerialKey::parse(std::string plainSerial) { - string parityStart = plainSerial.substr(0, 1); - string parityEnd = plainSerial.substr(plainSerial.length() - 1, 1); + string parityStart = plainSerial.substr(0, 1); + string parityEnd = plainSerial.substr(plainSerial.length() - 1, 1); - bool valid = false; + bool valid = false; - // check for parity chars { and }, record parity result, then remove them. - if (parityStart == "{" && parityEnd == "}") { - plainSerial = plainSerial.substr(1, plainSerial.length() - 2); + // 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; - } + // 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.setType(parts.at(1)); - m_name = parts.at(2); - 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_KeyType.setKeyType(parts.at(1)); - m_edition.setType(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; - } - } + if ((parts.size() == 8) + && (parts.at(0).find("v1") != string::npos)) { + // e.g.: {v1;basic;Bob;1;email;company name;1398297600;1398384000} + m_edition.setType(parts.at(1)); + m_name = parts.at(2); + 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_KeyType.setKeyType(parts.at(1)); + m_edition.setType(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; + return valid; } diff --git a/src/lib/shared/SerialKey.h b/src/lib/shared/SerialKey.h index abb16fca4..cfaf19da6 100644 --- a/src/lib/shared/SerialKey.h +++ b/src/lib/shared/SerialKey.h @@ -37,6 +37,7 @@ public: bool isExpired(time_t currentTime) const; bool isTrial() const; bool isTemporary() const; + bool isValid() const; time_t daysLeft(time_t currentTime) const; std::string email() const; Edition edition() const; @@ -62,7 +63,7 @@ private: unsigned m_userLimit; unsigned long long m_warnTime; unsigned long long m_expireTime; - SerialKeyEdition m_edition; + SerialKeyEdition m_edition; SerialKeyType m_KeyType; }; diff --git a/src/test/unittests/shared/SerialKeyTests.cpp b/src/test/unittests/shared/SerialKeyTests.cpp index e2dcd005f..4c7b09f12 100644 --- a/src/test/unittests/shared/SerialKeyTests.cpp +++ b/src/test/unittests/shared/SerialKeyTests.cpp @@ -156,55 +156,74 @@ TEST(SerialKeyTests, daysLeft_expiredV2TrialBasicSerial_returnZero) //Subscription license tests TEST(SerialKeyTests, isExpiring_validV2SubscriptionBasicSerial_returnFalse) { - // {v2;subscription;basic;Bob;1;email;company name;1;86400} - SerialKey serial("7B76323B737562736372697074696F6E3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B313B38363430307D"); - EXPECT_EQ(false, serial.isTrial()); - EXPECT_EQ(true, serial.isTemporary()); - EXPECT_FALSE(serial.isExpiring(0)); - EXPECT_EQ(kBasic, serial.edition()); + // {v2;subscription;basic;Bob;1;email;company name;1;86400} + SerialKey serial("7B76323B737562736372697074696F6E3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B313B38363430307D"); + EXPECT_EQ(false, serial.isTrial()); + EXPECT_EQ(true, serial.isTemporary()); + EXPECT_FALSE(serial.isExpiring(0)); + EXPECT_EQ(kBasic, serial.edition()); } TEST(SerialKeyTests, isExpiring_expiringV2SubscriptionBasicSerial_returnTrue) { - // {v2;subscription;basic;Bob;1;email;company name;0;86400} - SerialKey serial("7B76323B737562736372697074696F6E3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); - EXPECT_EQ(false, serial.isTrial()); - EXPECT_EQ(true, serial.isTemporary()); - EXPECT_EQ(true, serial.isExpiring(1)); + // {v2;subscription;basic;Bob;1;email;company name;0;86400} + SerialKey serial("7B76323B737562736372697074696F6E3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); + EXPECT_EQ(false, serial.isTrial()); + EXPECT_EQ(true, serial.isTemporary()); + EXPECT_EQ(true, serial.isExpiring(1)); } TEST(SerialKeyTests, isExpired_expiredV2SubscriptionBasicSerial_returnTrue) { - // {v2;subscription;basic;Bob;1;email;company name;0;86400} - SerialKey serial("7B76323B737562736372697074696F6E3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); - EXPECT_EQ(false, serial.isTrial()); - EXPECT_EQ(true, serial.isTemporary()); - EXPECT_EQ(true, serial.isExpired(86401)); + // {v2;subscription;basic;Bob;1;email;company name;0;86400} + SerialKey serial("7B76323B737562736372697074696F6E3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); + EXPECT_EQ(false, serial.isTrial()); + EXPECT_EQ(true, serial.isTemporary()); + EXPECT_EQ(true, serial.isExpired(86401)); } //toString method tests TEST(SerialKeyTests, toStringV2SubscriptionBasicSerialKey) { - //{v2;subscription;basic;Bob;1;email;company name;0;86400} - const std::string Expected = "7B76323B737562736372697074696F6E3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"; - SerialKey serial(Expected); - EXPECT_EQ(Expected, serial.toString()); + //{v2;subscription;basic;Bob;1;email;company name;0;86400} + const std::string Expected = "7B76323B737562736372697074696F6E3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"; + SerialKey serial(Expected); + EXPECT_EQ(Expected, serial.toString()); } TEST(SerialKeyTests, toStringV2TrialBasicSerialKey) { - //{v2;trial;basic;Bob;1;email;company name;0;86400} - const std::string Expected = "7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"; - SerialKey serial(Expected); - EXPECT_EQ(Expected, serial.toString()); + //{v2;trial;basic;Bob;1;email;company name;0;86400} + const std::string Expected = "7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"; + SerialKey serial(Expected); + EXPECT_EQ(Expected, serial.toString()); } TEST(SerialKeyTests, toStringV1BasicSerialKey) { - //{v1;basic;Bob;1;email;company name;0;0} - const std::string Expected = "7B76313B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B307D"; - SerialKey serial(Expected); - EXPECT_EQ(Expected, serial.toString()); + //{v1;basic;Bob;1;email;company name;0;0} + const std::string Expected = "7B76313B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B307D"; + SerialKey serial(Expected); + EXPECT_EQ(Expected, serial.toString()); +} + +TEST(SerialKeyTests, IsValidKey_false) +{ + //{v1;basic;Bob;1;email;company name;0;0} + SerialKey serial(kUnregistered); + EXPECT_EQ(false, serial.isValid()); +} + +TEST(SerialKeyTests, IsValidKey_true) +{ + SerialKey serial(kBasic); + EXPECT_EQ(true, serial.isValid()); +} + +TEST(SerialKeyTests, IsValidExpiredKey_false) +{ + SerialKey serial("7B76323B737562736372697074696F6E3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); + EXPECT_EQ(false, serial.isValid()); }