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.

253 lines
8.9KB

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