/* ============================================================================== This file is part of the JUCE library. Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. By using JUCE, you agree to the terms of both the JUCE 6 End-User License Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020). End User License Agreement: www.juce.com/juce-6-licence Privacy Policy: www.juce.com/juce-privacy-policy Or: You may also use this code under the terms of the GPL v3 (see www.gnu.org/licenses). JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE DISCLAIMED. ============================================================================== */ #pragma once #include "jucer_LicenseState.h" #include "jucer_LicenseQueryThread.h" //============================================================================== class LicenseController : private Timer { public: LicenseController() { checkLicense(); } //============================================================================== static LicenseState getGPLState() { return { LicenseState::Type::gpl, projucerMajorVersion, {}, {} }; } LicenseState getCurrentState() const noexcept { return state; } void setState (const LicenseState& newState) { if (state != newState) { state = newState; licenseStateToSettings (state, getGlobalProperties()); stateListeners.call ([] (LicenseStateListener& l) { l.licenseStateChanged(); }); } } void resetState() { setState ({}); } void signIn (const String& email, const String& password, std::function completionCallback) { licenseQueryThread.doSignIn (email, password, [this, completionCallback] (LicenseQueryThread::ErrorMessageAndType error, LicenseState newState) { completionCallback (error.first); setState (newState); }); } void cancelSignIn() { licenseQueryThread.cancelRunningJobs(); } //============================================================================== struct LicenseStateListener { virtual ~LicenseStateListener() = default; virtual void licenseStateChanged() = 0; }; void addListener (LicenseStateListener* listenerToAdd) { stateListeners.add (listenerToAdd); } void removeListener (LicenseStateListener* listenerToRemove) { stateListeners.remove (listenerToRemove); } private: //============================================================================== static const char* getLicenseStateValue (LicenseState::Type type) { switch (type) { case LicenseState::Type::gpl: return "GPL"; case LicenseState::Type::personal: return "personal"; case LicenseState::Type::educational: return "edu"; case LicenseState::Type::indie: return "indie"; case LicenseState::Type::pro: return "pro"; case LicenseState::Type::none: default: break; } return nullptr; } static LicenseState::Type getLicenseTypeFromValue (const String& d) { if (d == getLicenseStateValue (LicenseState::Type::gpl)) return LicenseState::Type::gpl; if (d == getLicenseStateValue (LicenseState::Type::personal)) return LicenseState::Type::personal; if (d == getLicenseStateValue (LicenseState::Type::educational)) return LicenseState::Type::educational; if (d == getLicenseStateValue (LicenseState::Type::indie)) return LicenseState::Type::indie; if (d == getLicenseStateValue (LicenseState::Type::pro)) return LicenseState::Type::pro; return LicenseState::Type::none; } static LicenseState licenseStateFromSettings (PropertiesFile& props) { if (auto licenseXml = props.getXmlValue ("license")) { // this is here for backwards compatibility with old-style settings files using XML text elements if (licenseXml->getChildElementAllSubText ("type", {}).isNotEmpty()) { auto stateFromOldSettings = [&licenseXml]() -> LicenseState { return { getLicenseTypeFromValue (licenseXml->getChildElementAllSubText ("type", {})), licenseXml->getChildElementAllSubText ("version", "-1").getIntValue(), licenseXml->getChildElementAllSubText ("username", {}), licenseXml->getChildElementAllSubText ("authToken", {}) }; }(); licenseStateToSettings (stateFromOldSettings, props); return stateFromOldSettings; } return { getLicenseTypeFromValue (licenseXml->getStringAttribute ("type", {})), licenseXml->getIntAttribute ("version", -1), licenseXml->getStringAttribute ("username", {}), licenseXml->getStringAttribute ("authToken", {}) }; } return {}; } static void licenseStateToSettings (const LicenseState& state, PropertiesFile& props) { props.removeValue ("license"); if (state.isSignedIn()) { XmlElement licenseXml ("license"); if (auto* typeString = getLicenseStateValue (state.type)) licenseXml.setAttribute ("type", typeString); licenseXml.setAttribute ("version", state.version); licenseXml.setAttribute ("username", state.username); licenseXml.setAttribute ("authToken", state.authToken); props.setValue ("license", &licenseXml); } props.saveIfNeeded(); } //============================================================================== void checkLicense() { if (state.authToken.isNotEmpty() && ! state.isGPL()) { auto completionCallback = [this] (LicenseQueryThread::ErrorMessageAndType error, LicenseState updatedState) { if (error == LicenseQueryThread::ErrorMessageAndType()) { setState (updatedState); } else if ((error.second == LicenseQueryThread::ErrorType::busy || error.second == LicenseQueryThread::ErrorType::cancelled || error.second == LicenseQueryThread::ErrorType::connectionError) && ! hasRetriedLicenseCheck) { hasRetriedLicenseCheck = true; startTimer (10000); } }; licenseQueryThread.checkLicenseValidity (state, std::move (completionCallback)); } } void timerCallback() override { stopTimer(); checkLicense(); } //============================================================================== #if JUCER_ENABLE_GPL_MODE LicenseState state = getGPLState(); #else LicenseState state = licenseStateFromSettings (getGlobalProperties()); #endif ListenerList stateListeners; LicenseQueryThread licenseQueryThread; bool hasRetriedLicenseCheck = false; //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LicenseController) };