The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

251 lines
8.9KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. #include "../jucer_Headers.h"
  18. #include "../Application/jucer_Application.h"
  19. #include "../Project Saving/jucer_ProjectExporter.h"
  20. #include "../Project/jucer_HeaderComponent.h"
  21. #include "jucer_LicenseController.h"
  22. #include "jucer_LicenseWebview.h"
  23. #include "jucer_LicenseThread.h"
  24. //==============================================================================
  25. const char* LicenseState::licenseTypeToString (LicenseState::Type type)
  26. {
  27. switch (type)
  28. {
  29. case Type::notLoggedIn: return "<notLoggedIn>";
  30. case Type::noLicenseChosenYet: return "<noLicenseChosenYet>";
  31. case Type::GPL: return "JUCE GPL";
  32. case Type::personal: return "JUCE Personal";
  33. case Type::edu: return "JUCE Education";
  34. case Type::indie: return "JUCE Indie";
  35. case Type::pro: return "JUCE Pro";
  36. default: return "<unknown>";
  37. }
  38. }
  39. static const char* getLicenseStateValue (LicenseState::Type type)
  40. {
  41. switch (type)
  42. {
  43. case LicenseState::Type::GPL: return "GPL";
  44. case LicenseState::Type::personal: return "personal";
  45. case LicenseState::Type::edu: return "edu";
  46. case LicenseState::Type::indie: return "indie";
  47. case LicenseState::Type::pro: return "pro";
  48. default: return nullptr;
  49. }
  50. }
  51. static LicenseState::Type getLicenseTypeFromValue (const String& d)
  52. {
  53. if (d == getLicenseStateValue (LicenseState::Type::GPL)) return LicenseState::Type::GPL;
  54. if (d == getLicenseStateValue (LicenseState::Type::personal)) return LicenseState::Type::personal;
  55. if (d == getLicenseStateValue (LicenseState::Type::edu)) return LicenseState::Type::edu;
  56. if (d == getLicenseStateValue (LicenseState::Type::indie)) return LicenseState::Type::indie;
  57. if (d == getLicenseStateValue (LicenseState::Type::pro)) return LicenseState::Type::pro;
  58. return LicenseState::Type::noLicenseChosenYet;
  59. }
  60. //==============================================================================
  61. struct LicenseController::ModalCompletionCallback : ModalComponentManager::Callback
  62. {
  63. ModalCompletionCallback (LicenseController& controller) : owner (controller) {}
  64. void modalStateFinished (int returnValue) override { owner.modalStateFinished (returnValue); }
  65. LicenseController& owner;
  66. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ModalCompletionCallback)
  67. };
  68. //==============================================================================
  69. LicenseController::LicenseController()
  70. #if (! JUCER_ENABLE_GPL_MODE)
  71. : state (licenseStateFromSettings (ProjucerApplication::getApp().settings->getGlobalProperties()))
  72. #endif
  73. {
  74. #if JUCER_ENABLE_GPL_MODE
  75. state.type = LicenseState::Type::GPL;
  76. state.username = "GPL mode";
  77. #else
  78. thread = new LicenseThread (*this, false);
  79. #endif
  80. }
  81. LicenseController::~LicenseController()
  82. {
  83. thread = nullptr;
  84. closeWebview (-1);
  85. }
  86. void LicenseController::logout()
  87. {
  88. jassert (MessageManager::getInstance()->isThisTheMessageThread());
  89. #if ! JUCER_ENABLE_GPL_MODE
  90. thread = nullptr;
  91. updateState ({});
  92. #if ! JUCE_LINUX
  93. WebBrowserComponent::clearCookies();
  94. #endif
  95. thread = new LicenseThread (*this, false);
  96. #endif
  97. }
  98. void LicenseController::chooseNewLicense()
  99. {
  100. jassert (MessageManager::getInstance()->isThisTheMessageThread());
  101. #if ! JUCER_ENABLE_GPL_MODE
  102. thread = nullptr;
  103. thread = new LicenseThread (*this, true);
  104. #endif
  105. }
  106. //==============================================================================
  107. void LicenseController::closeWebview (int result)
  108. {
  109. if (licenseWebview != nullptr)
  110. licenseWebview->exitModalState (result);
  111. }
  112. void LicenseController::modalStateFinished (int result)
  113. {
  114. licenseWebview = nullptr;
  115. if (result == -1 && (state.type == LicenseState::Type::notLoggedIn
  116. || state.type == LicenseState::Type::noLicenseChosenYet))
  117. JUCEApplication::getInstance()->systemRequestedQuit();
  118. }
  119. void LicenseController::ensureLicenseWebviewIsOpenWithPage (const String& param)
  120. {
  121. if (licenseWebview != nullptr)
  122. {
  123. licenseWebview->goToURL (param);
  124. licenseWebview->toFront (true);
  125. }
  126. else
  127. {
  128. #if ! JUCE_LINUX
  129. WebBrowserComponent::clearCookies();
  130. #endif
  131. licenseWebview = new LicenseWebview (new ModalCompletionCallback (*this), param);
  132. }
  133. }
  134. void LicenseController::queryWebview (const String& startURL, const String& valueToQuery,
  135. HashMap<String, String>& result)
  136. {
  137. ensureLicenseWebviewIsOpenWithPage (startURL);
  138. licenseWebview->setPageCallback ([this,valueToQuery,&result] (const String& cmd, const HashMap<String, String>& params)
  139. {
  140. if (valueToQuery.isEmpty() || cmd == valueToQuery)
  141. {
  142. result.clear();
  143. for (HashMap<String, String>::Iterator it = params.begin(); it != params.end(); ++it)
  144. result.set (it.getKey(), it.getValue());
  145. if (thread != nullptr && ! thread->threadShouldExit())
  146. thread->finished.signal();
  147. }
  148. });
  149. licenseWebview->setNewWindowCallback ([this, &result] (const String& url)
  150. {
  151. if (url.endsWith ("get-juce/indie") || url.endsWith ("get-juce/pro"))
  152. {
  153. result.clear();
  154. result.set ("page-redirect", url);
  155. if (thread != nullptr && ! thread->threadShouldExit())
  156. thread->finished.signal();
  157. }
  158. });
  159. }
  160. void LicenseController::updateState (const LicenseState& newState)
  161. {
  162. auto& props = ProjucerApplication::getApp().settings->getGlobalProperties();
  163. state = newState;
  164. licenseStateToSettings (state, props);
  165. listeners.call (&StateChangedCallback::licenseStateChanged, state);
  166. }
  167. LicenseState LicenseController::licenseStateFromSettings (PropertiesFile& props)
  168. {
  169. ScopedPointer<XmlElement> licenseXml = props.getXmlValue ("license");
  170. if (licenseXml != nullptr)
  171. {
  172. LicenseState result;
  173. result.type = getLicenseTypeFromValue (licenseXml->getChildElementAllSubText ("type", {}));
  174. result.username = licenseXml->getChildElementAllSubText ("username", {});
  175. result.email = licenseXml->getChildElementAllSubText ("email", {});
  176. result.authToken = licenseXml->getChildElementAllSubText ("authToken", {});
  177. MemoryOutputStream imageData;
  178. Base64::convertFromBase64 (imageData, licenseXml->getChildElementAllSubText ("avatar", {}));
  179. result.avatar = ImageFileFormat::loadFrom (imageData.getData(), imageData.getDataSize());
  180. return result;
  181. }
  182. return {};
  183. }
  184. void LicenseController::licenseStateToSettings (const LicenseState& state, PropertiesFile& props)
  185. {
  186. props.removeValue ("license");
  187. if (state.type != LicenseState::Type::notLoggedIn
  188. && state.username.isNotEmpty() && state.authToken.isNotEmpty())
  189. {
  190. XmlElement licenseXml ("license");
  191. if (auto* typeString = getLicenseStateValue (state.type))
  192. licenseXml.createNewChildElement ("type")->addTextElement (typeString);
  193. licenseXml.createNewChildElement ("username")->addTextElement (state.username);
  194. licenseXml.createNewChildElement ("email") ->addTextElement (state.email);
  195. // TODO: encrypt authToken
  196. licenseXml.createNewChildElement ("authToken")->addTextElement (state.authToken);
  197. MemoryOutputStream imageData;
  198. if (state.avatar.isValid() && PNGImageFormat().writeImageToStream (state.avatar, imageData))
  199. licenseXml.createNewChildElement ("avatar")->addTextElement (Base64::toBase64 (imageData.getData(), imageData.getDataSize()));
  200. props.setValue ("license", &licenseXml);
  201. }
  202. props.saveIfNeeded();
  203. }