+
+namespace synergy::gui {
+
+/**
+ * @param filePath Path to the .env file.
+ * @param envVars Somewhere to save strings for the lifetime of the app.
+ */
+void dotenv(const QString &filePath);
+
+} // namespace synergy::gui
diff --git a/src/lib/gui/license_notices.cpp b/src/lib/gui/license_notices.cpp
new file mode 100644
index 000000000..a399a0d25
--- /dev/null
+++ b/src/lib/gui/license_notices.cpp
@@ -0,0 +1,76 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2024 Synergy 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 "license_notices.h"
+
+#include "constants.h"
+#include "license/License.h"
+
+using License = synergy::license::License;
+
+namespace synergy::gui {
+
+QString trialLicenseNotice(const License &license);
+QString subscriptionLicenseNotice(const License &license);
+
+QString licenseNotice(const License &license) {
+ if (license.isTrial()) {
+ return trialLicenseNotice(license);
+ } else if (license.isSubscription()) {
+ return subscriptionLicenseNotice(license);
+ } else {
+ qFatal("license notice only for time limited licenses");
+ }
+}
+
+QString trialLicenseNotice(const License &license) {
+ const QString buyLink =
+ QString(kLinkBuy).arg(kUrlPurchase).arg(kLinkStyleWhite);
+ if (license.isExpired()) {
+ return QString("Your trial has expired. %1
").arg(buyLink);
+ } else {
+ auto daysLeft = license.daysLeft().count();
+ if (daysLeft <= 0) {
+ return QString("Your trial expires today. %1
").arg(buyLink);
+ } else {
+ return QString("Your trial expires in %1 %2. %3
")
+ .arg(daysLeft)
+ .arg((daysLeft == 1) ? "day" : "days")
+ .arg(buyLink);
+ }
+ }
+}
+
+QString subscriptionLicenseNotice(const License &license) {
+ const QString renewLink =
+ QString(kLinkRenew).arg(kUrlPurchase).arg(kLinkStyleWhite);
+ if (license.isExpired()) {
+ return QString("Your license has expired. %1
").arg(renewLink);
+ } else {
+ auto daysLeft = license.daysLeft().count();
+ if (daysLeft <= 0) {
+ return QString("Your license expires today. %1
").arg(renewLink);
+ } else {
+ return QString("Your license expires in %1 %2. %3
")
+ .arg(daysLeft)
+ .arg((daysLeft == 1) ? "day" : "days")
+ .arg(renewLink);
+ }
+ }
+}
+
+} // namespace synergy::gui
diff --git a/src/gui/src/ActivationNotifier.h b/src/lib/gui/license_notices.h
similarity index 52%
rename from src/gui/src/ActivationNotifier.h
rename to src/lib/gui/license_notices.h
index 554fe536f..153623b0e 100644
--- a/src/gui/src/ActivationNotifier.h
+++ b/src/lib/gui/license_notices.h
@@ -1,6 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
- * Copyright (C) 2015 Synergy Ltd.
+ * Copyright (C) 2024 Synergy Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -15,33 +15,14 @@
* along with this program. If not, see .
*/
-#ifndef ACTIVATIONNOTIFIER_H
-#define ACTIVATIONNOTIFIER_H
+#pragma once
-#include
+#include "license/License.h"
-class ActivationNotifier : public QObject {
- Q_OBJECT
-public:
- explicit ActivationNotifier(QObject *parent = 0);
+#include
- void setIdentity(QString identity);
- void setUpdateInfo(
- QString const &fromVersion, QString const &toVersion,
- QString const &serialKey);
+namespace synergy::gui {
-public slots:
- void notify();
- void notifyUpdate();
+QString licenseNotice(const synergy::license::License &license);
-signals:
- void finished();
-
-private:
- QString m_Identity;
- QString m_fromVersion;
- QString m_toVersion;
- QString m_serialKey;
-};
-
-#endif // ACTIVATIONNOTIFIER_H
+} // namespace synergy::gui
diff --git a/src/lib/ipc/IpcClient.cpp b/src/lib/ipc/IpcClient.cpp
index c9bd18797..1cf83634b 100644
--- a/src/lib/ipc/IpcClient.cpp
+++ b/src/lib/ipc/IpcClient.cpp
@@ -17,9 +17,9 @@
#include "ipc/IpcClient.h"
#include "base/TMethodEventJob.h"
+#include "global/Ipc.h"
#include "ipc/IpcMessage.h"
#include "ipc/IpcServerProxy.h"
-#include "shared/Ipc.h"
//
// IpcClient
diff --git a/src/lib/ipc/IpcClientProxy.cpp b/src/lib/ipc/IpcClientProxy.cpp
index 2c9949e90..3ee3843d8 100644
--- a/src/lib/ipc/IpcClientProxy.cpp
+++ b/src/lib/ipc/IpcClientProxy.cpp
@@ -19,10 +19,10 @@
#include "base/Log.h"
#include "base/TMethodEventJob.h"
+#include "global/Ipc.h"
#include "io/IStream.h"
#include "ipc/IpcMessage.h"
#include "ipc/IpcSettingMessage.h"
-#include "shared/Ipc.h"
#include "synergy/ProtocolUtil.h"
//
diff --git a/src/lib/ipc/IpcClientProxy.h b/src/lib/ipc/IpcClientProxy.h
index 7362d16a2..a41fda093 100644
--- a/src/lib/ipc/IpcClientProxy.h
+++ b/src/lib/ipc/IpcClientProxy.h
@@ -21,7 +21,7 @@
#include "arch/IArchMultithread.h"
#include "base/Event.h"
#include "base/EventTypes.h"
-#include "shared/Ipc.h"
+#include "global/Ipc.h"
namespace synergy {
class IStream;
diff --git a/src/lib/ipc/IpcLogOutputter.cpp b/src/lib/ipc/IpcLogOutputter.cpp
index 2b4213100..bc322e972 100644
--- a/src/lib/ipc/IpcLogOutputter.cpp
+++ b/src/lib/ipc/IpcLogOutputter.cpp
@@ -24,11 +24,11 @@
#include "base/EventQueue.h"
#include "base/TMethodEventJob.h"
#include "base/TMethodJob.h"
+#include "global/Ipc.h"
#include "ipc/IpcClientProxy.h"
#include "ipc/IpcMessage.h"
#include "ipc/IpcServer.h"
#include "mt/Thread.h"
-#include "shared/Ipc.h"
enum EIpcLogOutputter {
kBufferMaxSize = 1000,
diff --git a/src/lib/ipc/IpcLogOutputter.h b/src/lib/ipc/IpcLogOutputter.h
index a38a3380e..06deeee66 100644
--- a/src/lib/ipc/IpcLogOutputter.h
+++ b/src/lib/ipc/IpcLogOutputter.h
@@ -21,7 +21,7 @@
#include "arch/Arch.h"
#include "arch/IArchMultithread.h"
#include "base/ILogOutputter.h"
-#include "shared/Ipc.h"
+#include "global/Ipc.h"
#include
diff --git a/src/lib/ipc/IpcMessage.cpp b/src/lib/ipc/IpcMessage.cpp
index 955564b39..dc51f3518 100644
--- a/src/lib/ipc/IpcMessage.cpp
+++ b/src/lib/ipc/IpcMessage.cpp
@@ -17,7 +17,7 @@
*/
#include "ipc/IpcMessage.h"
-#include "shared/Ipc.h"
+#include "global/Ipc.h"
IpcMessage::IpcMessage(IpcMessageType type) : m_type(type) {}
diff --git a/src/lib/ipc/IpcMessage.h b/src/lib/ipc/IpcMessage.h
index 594d6c666..dcd417043 100644
--- a/src/lib/ipc/IpcMessage.h
+++ b/src/lib/ipc/IpcMessage.h
@@ -19,7 +19,7 @@
#include "base/Event.h"
#include "base/String.h"
-#include "shared/Ipc.h"
+#include "global/Ipc.h"
class IpcMessage : public EventData {
public:
diff --git a/src/lib/ipc/IpcServer.cpp b/src/lib/ipc/IpcServer.cpp
index 0c3f6f730..bf1dc87d4 100644
--- a/src/lib/ipc/IpcServer.cpp
+++ b/src/lib/ipc/IpcServer.cpp
@@ -22,11 +22,11 @@
#include "base/IEventQueue.h"
#include "base/Log.h"
#include "base/TMethodEventJob.h"
+#include "global/Ipc.h"
#include "io/IStream.h"
#include "ipc/IpcClientProxy.h"
#include "ipc/IpcMessage.h"
#include "net/IDataSocket.h"
-#include "shared/Ipc.h"
//
// IpcServer
diff --git a/src/lib/ipc/IpcServer.h b/src/lib/ipc/IpcServer.h
index 453a9abe9..c21998599 100644
--- a/src/lib/ipc/IpcServer.h
+++ b/src/lib/ipc/IpcServer.h
@@ -20,9 +20,9 @@
#include "arch/Arch.h"
#include "base/EventTypes.h"
+#include "global/Ipc.h"
#include "net/NetworkAddress.h"
#include "net/TCPListenSocket.h"
-#include "shared/Ipc.h"
#include
diff --git a/src/lib/ipc/IpcServerProxy.cpp b/src/lib/ipc/IpcServerProxy.cpp
index 25578e93f..2e34f5879 100644
--- a/src/lib/ipc/IpcServerProxy.cpp
+++ b/src/lib/ipc/IpcServerProxy.cpp
@@ -20,9 +20,9 @@
#include "base/Log.h"
#include "base/TMethodEventJob.h"
+#include "global/Ipc.h"
#include "io/IStream.h"
#include "ipc/IpcMessage.h"
-#include "shared/Ipc.h"
#include "synergy/ProtocolUtil.h"
//
diff --git a/src/lib/license/CMakeLists.txt b/src/lib/license/CMakeLists.txt
new file mode 100644
index 000000000..024ecda9e
--- /dev/null
+++ b/src/lib/license/CMakeLists.txt
@@ -0,0 +1,26 @@
+# Synergy -- mouse and keyboard sharing utility
+# Copyright (C) 2012-2024 Symless Ltd.
+# Copyright (C) 2009-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
+# 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(ADD_HEADERS_TO_SOURCES)
+ list(APPEND sources ${headers})
+endif()
+
+add_library(license STATIC ${sources})
+
+target_link_libraries(license arch base)
diff --git a/src/lib/license/License.cpp b/src/lib/license/License.cpp
new file mode 100644
index 000000000..cc10c07bc
--- /dev/null
+++ b/src/lib/license/License.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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 "License.h"
+
+#include "Product.h"
+#include "license/SerialKey.h"
+#include "license/parse_serial_key.h"
+
+#include
+#include
+
+using namespace std::chrono;
+
+namespace synergy::license {
+
+License::License(const std::string &hexString)
+ : m_serialKey(parseSerialKey(hexString)) {}
+
+License::License(const SerialKey &serialKey) : m_serialKey(serialKey) {
+ if (!m_serialKey.isValid) {
+ throw InvalidSerialKey();
+ }
+}
+
+bool License::isTrial() const { return m_serialKey.type.isTrial(); }
+
+bool License::isSubscription() const {
+ return m_serialKey.type.isSubscription();
+}
+
+bool License::isTimeLimited() const { return m_serialKey.type.isTimeLimited(); }
+
+bool License::isTlsAvailable() const {
+ return m_serialKey.product.isTlsAvailable();
+}
+
+Edition License::productEdition() const {
+ return m_serialKey.product.edition();
+}
+
+bool License::isExpiring() const {
+ if (!isTimeLimited()) {
+ return false;
+ }
+
+ if (!m_serialKey.warnTime.has_value()) {
+ throw NoTimeLimitError();
+ }
+
+ return m_nowFunc() >= m_serialKey.warnTime.value();
+}
+
+bool License::isExpired() const {
+ if (!isTimeLimited()) {
+ return false;
+ }
+
+ if (!m_serialKey.expireTime.has_value()) {
+ throw NoTimeLimitError();
+ }
+
+ return m_nowFunc() >= m_serialKey.expireTime.value();
+}
+
+days License::daysLeft() const {
+ if (!m_serialKey.expireTime.has_value()) {
+ throw NoTimeLimitError();
+ }
+
+ auto expireTime = m_serialKey.expireTime.value();
+
+ auto timeLeft = expireTime - m_nowFunc();
+ return duration_cast(timeLeft);
+}
+
+std::string License::productName() const {
+ auto name = m_serialKey.product.name();
+ if (m_serialKey.type.isTrial()) {
+ name += " (Trial)";
+ }
+ return name;
+}
+
+} // namespace synergy::license
diff --git a/src/lib/license/License.h b/src/lib/license/License.h
new file mode 100644
index 000000000..c278a7d96
--- /dev/null
+++ b/src/lib/license/License.h
@@ -0,0 +1,93 @@
+/*
+ * 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 "SerialKey.h"
+
+#include
+#include
+#include
+#include
+
+class Server;
+class LicenseHandler;
+class LicenseTests;
+
+namespace synergy::license {
+
+class License {
+ friend class ::Server;
+ friend class ::LicenseHandler;
+ friend class ::LicenseTests;
+
+ using days = std::chrono::days;
+ using system_clock = std::chrono::system_clock;
+ using time_point = system_clock::time_point;
+ using NowFunc = std::function;
+ using LicenseError = std::runtime_error;
+
+public:
+ explicit License(const SerialKey &serialKey);
+ explicit License(const std::string &hexString);
+
+ friend bool operator==(License const &lhs, License const &rhs) {
+ return lhs.m_serialKey == rhs.m_serialKey;
+ }
+
+ bool isValid() const { return m_serialKey.isValid; }
+ bool isExpiring() const;
+ bool isExpired() const;
+ bool isTrial() const;
+ bool isSubscription() const;
+ bool isTimeLimited() const;
+ bool isTlsAvailable() const;
+ days daysLeft() const;
+ Edition productEdition() const;
+ std::string productName() const;
+ const SerialKey &serialKey() const { return m_serialKey; }
+ void invalidate() { m_serialKey = SerialKey::invalid(); }
+
+ class InvalidSerialKey : public LicenseError {
+ public:
+ explicit InvalidSerialKey() : LicenseError("invalid serial key") {}
+ };
+
+ class NoTimeLimitError : public LicenseError {
+ public:
+ explicit NoTimeLimitError()
+ : LicenseError("serial key has no time limit") {}
+ };
+
+protected:
+ void setNowFunc(const NowFunc &nowFunc) { m_nowFunc = nowFunc; }
+
+private:
+ // for intentionality, force use of `invalid()` static function.
+ License() = default;
+
+ // prevent copy, so that changes can be reflected in one instance.
+ License(const License &) = default;
+ License &operator=(const License &) = default;
+
+ static License invalid() { return License(); }
+
+ SerialKey m_serialKey = SerialKey::invalid();
+ NowFunc m_nowFunc = []() { return system_clock::now(); };
+};
+
+} // namespace synergy::license
diff --git a/src/lib/license/Product.cpp b/src/lib/license/Product.cpp
new file mode 100644
index 000000000..c4116de0e
--- /dev/null
+++ b/src/lib/license/Product.cpp
@@ -0,0 +1,121 @@
+/*
+ * 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